I have this code in lrvViewModel.swift
func getVerificationID (phoneNumber: String) -> Future<String?, Error> {
return Future<String?, Error> { promise in
PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil) { (verificationID, error) in
if let e = error {
promise(.failure(e))
return
}
print("verification worked")
self.defaults.set(verificationID, forKey: "authVerificationID")
return promise(.success(verificationID))
}
}
}
and then i call and subscribe to the Publisher in another file like this
let _ = lrvViewModel.getVerificationID(phoneNumber: (lrvViewController?.textField.text)!)
.sink(receiveCompletion: {
print("Error worked")
// does a bunch of stuff
}, receiveValue: {
print("completion worked")
// does a bunch of stuff
})
I don't get any buildtime errors, but whenever I run the app the GetVerificationID function runs fine (prints "Verification worked"), but the code within .sink doesn't run (I don't get any print statements). What's going on?
Edit:
My solution was to give up on combine and go back to RXSwift where the code is simply:
var validateObs = PublishSubject<Any>()
func getVerificationID (phoneNumber: String) {
PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil) { (verificationID, error) in
if let e = error {
print("v error")
self.validateObs.onError(e)
return
}
self.defaults.set(verificationID, forKey: "authVerificationID")
self.validateObs.onCompleted()
}
}
and
lrvViewModel.getVerificationID(phoneNumber: (lrvViewController?.textField.text)!)
let _ = lrvViewModel.validateObs.subscribe(onError: {
let e = $0
print(e.localizedDescription)
// do stuff
}, onCompleted: {
// do stuff
})
Was hoping to not rely on a dependency but RxSwift implementation was much easier.
If someone knows the solution to the Combine Future problem please post! I would still like to know wtf is happening. It's very possible (and likely) I'm just using combine wrong.
Edit 2:
Was using combine wrong. I can duplicate the code I had with RXSwift like this:
let verifyPub = PassthroughSubject<Any, Error>()
func getVerificationID (phoneNumber: String) {
PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil) { (verificationID, error) in
if let e = error {
self.verifyPub.send(completion: .failure(e))
return
}
print("verification worked")
self.defaults.set(verificationID, forKey: "authVerificationID")
self.verifyPub.send(completion: .finished)
}
}
and
let subs = Set<AnyCancellable>()
let pub = lrvViewModel.verifyPub
.sink(receiveCompletion: { completion in
if case let .failure(error) = completion {
print("Error worked")
// do stuff
} else {
print("completion worked")
// do stuff
}
}, receiveValue: { _ in
print("this will never happen")
}).store(in: &subs)
I didnt' understand that in combine there are only two results to a sink, a completion or a value, and that completion is split up into multiple cases. Whereas in RxSwift you have OnNext, OnComplete, and OnError.
Shoutout to the book on Combine from raywanderlich.com. Good stuff.
What's going on is that your .sink
is not followed by a .store
command, so the pipeline goes out of existence before any value has a chance to come down it.
Your assignment of the pipeline to the empty _
effectively masks the problem. The compiler tried to warn you, and you shut it down.