Search code examples
iosswiftuicombine

PassthroughSubject with completion handler output?


I'm just getting started with Combine. I have these questions for this situation:

  1. Is it accepted to have a tuple as a PassthroughSubject output?
  2. Is it accepted to have a completion handler as part of the PassthroughSubject output?

Example situation:

A SwiftUI log in view where I hand off logging in to another class and expect a result back:

struct LogInView: View {
    var loginSubject = PassthroughSubject<(username: String, password: String, completion: (Error?) -> Void), Never>()         

    var body: some View {
        Button {
            loginSubject.send((username: "Jim", password: "qwerty123", completion: { error in
                if let error = error {
                    // handle error
                } else {
                    // navigate to app
                }
            }))
        } label: {
            Text("Log in")
        }
    }
}

I would like to know other possible solutions to this scenario (I'm not able to use the 'login helper' class directly in the SwiftUI view due to 'LogInView' being in a package and the 'log in helper' being in the main app) and/or if this would be generally accepted as a solution.


Solution

    1. Yes, it's very common.
    2. No, using a completion handler like this is working against Combine's inbuilt completion handling. Rather than using a passthrough, you should instead have a function that takes a username and a password and produces a publisher, and subscribing to that publisher will give you your completion/output handling. Such a function would usually live in an ObservableObject that you inject into your view hierarchy as an @EnvironmentObject.

    Further reading: https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views