2017-02-16 12 views
13

Mam utworzoną poniżej funkcję z łańcuchowaniem wielu obserwowalnych, ale cokolwiek robię to nie wydaje się wywoływać completed? to tylko powrót następuje:flatMap Nie wraca onCompleted

(facebookSignInAndFetchData()) -> subscribed 
(facebookSignInAndFetchData()) -> Event next(()) 

chociaż kiedy debug z obserwable indywidualnie wszyscy wrócą completed

tu jest mój funkcji łańcuchowym

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) 
    } 
}() 
+1

Wygląda dobrze. Czy możesz dodać implementacje rx_authenticate i fetchProfileData? – ULazdins

+0

to jest teraz dodane. z góry dziękuję –

+1

Czy możesz również dodać definicję 'obserwatoraFacebook'? – tomahh

Odpowiedz

5

rozpoczyna łańcuch z wywołaniem observerFacebook, który zwraca się zaobserwować, że będą emitować wartości każdym facebookButton jest na podsłuchu.

To obserwowalne zostanie zakończone dopiero po zwolnieniu facebookButton, najprawdopodobniej po usunięciu kontrolera widoku z ekranu.

Reszta łańcucha będzie map lub flatMap, ale nigdy nie wymuszaj zakończenia, ponieważ kolejne naciśnięcie spowoduje ponowne uruchomienie całego łańcucha.

łatwy sposobem rozwiązania tego byłoby dodać wywołanie do take(1) na facebookButton.rx.tap, tak że funkcja będzie zdefiniowane tak:

private lazy var observerFacebook: Observable<FacebookProvider>! = { 
    self.facebookButton.rx.tap 
    .take(1) 
    .map { 
     return FacebookProvider(parentController: self) 
    } 
}() 

Teraz observerFacebookbędzie zakończona po pierwszym dotknij i powinieneś zobaczyć połączenie z onCompleted.

Zauważ, że musisz zapisać się ponownie do łańcucha na temat błędów, jeśli chcesz wykonać je ponownie, gdy inny kran przychodzi.

+0

Jeśli ktoś tu wyląduje szukając odpowiedzi na rxjava, idiomem, którego używam jest 'Observable.create (s -> { s.onNext (new Object()); emitter = s;}). flatMap ($ -> realObservable) ', a następnie' emitter.onComplete() 'propaguje' onComplete() 'do subskrybenta. –