我创建了下面的函数,并链接了多个observable,但无论我做什么,它似乎都不会调用completed
?它只返回以下内容:
(facebookSignInAndFetchData()) -> subscribed
(facebookSignInAndFetchData()) -> Event next(())
即使单独观察debug
观察者,他们都会返回completed
这是我的链接功能
func facebookSignInAndFetchData() {
observerFacebook.flatMap { (provider: FacebookProvider) in
return provider.login()
}.flatMap { token in
return self.loginViewModel.rx_authenticate(token: token)
}.flatMap {
return self.loginViewModel.fetchProfileData()
}.debug().subscribe(onError: { error in
//Guard unknown ErrorType
guard let err = error as? AuthError else {
//Unknown error message
self.alertHelper.presentAlert(L10n.unknown)
return
}
//error message handling
switch err {
case .notLoggedIn:
print("not logged in")
break
default:
self.alertHelper.presentAlert(err.description)
}
}, onCompleted: {
self.goToInitialController()
}).addDisposableTo(self.disposeBag)
}
rx_authenticate
func rx_authenticate(token: String) -> Observable<Void> {
return Observable.create({ observer in
let credentials = SyncCredentials.facebook(token: token)
SyncUser.logIn(with: credentials, server: URL(string: Globals.serverURL)!, onCompletion: { user, error in
//Error while authenticating
guard error == nil else {
print("error while authenticating: \(error!)")
observer.onError(AuthError.unknown)
return
}
//Error while parsing user
guard let responseUser = user else {
print("error while authenticating: \(error!)")
observer.onError(AuthError.unknown)
return
}
//Authenticated
setDefaultRealmConfiguration(with: responseUser)
//next
observer.onNext()
//completed
observer.onCompleted()
})
return Disposables.create()
})
}
fetchProfileData
func fetchProfileData() -> Observable<Void> {
return Observable.create({ observer in
//Fetch facebookData
let params = ["fields" : "name, picture.width(480)"]
let graphRequest = GraphRequest(graphPath: "me", parameters: params)
graphRequest.start {
(urlResponse, requestResult) in
switch requestResult {
case .failed(_):
//Network error
observer.onError(AuthError.noConnection)
break
case .success(let graphResponse):
if let responseDictionary = graphResponse.dictionaryValue {
guard let identity = SyncUser.current?.identity else {
//User not logged in
observer.onError(AuthError.noUserIdentity)
return
}
//Name
let name = responseDictionary["name"] as! String
//Image dictionary
let pictureDic = responseDictionary["picture"] as! [String: Any]
let dataDic = pictureDic["data"] as! [String: Any]
let imageHeight = dataDic["height"] as! Int
let imageWidth = dataDic["width"] as! Int
let url = dataDic["url"] as! String
//Create Person object
let loggedUser = Person()
loggedUser.id = identity
loggedUser.name = name
//Create photo object
let photo = Photo()
photo.height = imageHeight
photo.width = imageWidth
photo.url = url
//Append photo object to person object
loggedUser.profileImage = photo
//Save userData
let realm = try! Realm()
try! realm.write {
realm.add(loggedUser, update: true)
}
//next
observer.onNext()
//completed
observer.onCompleted()
} else {
//Could not retrieve responseData
observer.onError(AuthError.noResponse)
}
}
}
return Disposables.create()
})
}
observerFacebook
//FacebookProvider
private lazy var observerFacebook: Observable<FacebookProvider>! = {
self.facebookButton.rx.tap.map {
return FacebookProvider(parentController: self)
}
}()
答案 0 :(得分:6)
链从调用observerFacebook
开始,它返回一个可以在每次点击facebookButton
时发出值的observable。
这个observable只会在facebookButton
被释放时完成,很可能是当从屏幕上移除持有它的视图控制器时。
链的其余部分将map
或flatMap
,但永远不会强制完成,因为另一个点击将再次触发整个链。
easy 解决此问题的方法是在take(1)
上添加对facebookButton.rx.tap
的调用,以便定义函数如下:
private lazy var observerFacebook: Observable<FacebookProvider>! = {
self.facebookButton.rx.tap
.take(1)
.map {
return FacebookProvider(parentController: self)
}
}()
现在,observerFacebook
将在第一次点按后完成,您应该会看到对onCompleted
的调用。
请注意,如果您想在另一次点按时再次执行此操作,则需要重新订阅错误链。