flatMap 不返回 onCompleted
Posted
技术标签:
【中文标题】flatMap 不返回 onCompleted【英文标题】:flatMap Not returning onCompleted 【发布时间】:2017-02-16 13:23:55 【问题描述】:我创建了下面的函数,链接了多个可观察对象,但是无论我做什么,它似乎都没有调用 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()
)
观察者Facebook
//FacebookProvider
private lazy var observerFacebook: Observable<FacebookProvider>! =
self.facebookButton.rx.tap.map
return FacebookProvider(parentController: self)
()
【问题讨论】:
看起来不错。可以添加 rx_authenticate 和 fetchProfileData 实现吗? 现在已添加。提前谢谢你 你还能为observerFacebook
添加定义吗?
你也需要登录功能吗? observerFacebook
已添加
这两个函数看起来都不错 - 应该总是以完成或错误完成。你能检查一下这是否正确——observer.onCompleted 都被调用了吗?
【参考方案1】:
该链从调用observerFacebook
开始,它返回一个可观察对象,每次点击facebookButton
时都会发出值。
这个 observable 只有在 facebookButton
被释放时才会完成,很可能是当持有它的视图控制器从屏幕上移除时。
链的其余部分将map
或flatMap
,但永远不会强制完成,因为另一个点击会再次触发整个链。
解决此问题的简单方法是在facebookButton.rx.tap
上添加对take(1)
的调用,以便函数定义如下:
private lazy var observerFacebook: Observable<FacebookProvider>! =
self.facebookButton.rx.tap
.take(1)
.map
return FacebookProvider(parentController: self)
()
现在,observerFacebook
将在第一次点击后完成,您应该会看到对 onCompleted
的调用。
请注意,如果您想在另一个点击时再次执行它,则需要重新订阅错误链。
【讨论】:
如果其他人来到这里寻找 rxjava 的答案,我使用的成语是Observable.create(s -> s.onNext(new Object()); emitter = s; ).flatMap($ -> realObservable)
,然后 emitter.onComplete()
会将 onComplete()
传播给订阅者。以上是关于flatMap 不返回 onCompleted的主要内容,如果未能解决你的问题,请参考以下文章
特征的 flatMap writeValue 不返回 Observable
spark 的一些常用函数 filter,map,flatMap,lookup ,reduce,groupByKey