RxSwift以正确的顺序链接两个信号

时间:2017-08-31 08:41:54

标签: swift swift3 rx-swift

所以基本上我需要执行两个动作:

  • 首先登录
  • 第二个是获取用户个人资料

必须以正确的顺序完成它们,因为如果没有先登录,就无法完成用户配置文件。

所以我有一堆看起来像这样的代码:

func signIn(signinParameters: SignInParameters) -> Observable<SignInResult> {
        return Observable<SignInResult>.create { [unowned self] observer in

            self.signinParameters = signinParameters

            self.apiConnector
                .signIn(with: signinParameters)
                .do(onNext: { [weak self] signinResult in

                    self!.apiConnector
                        .get()
                        .do(onNext: { user in

                            let realm = RealmManager.shared.newRealm()!

                            let realmUser = RealmUser()
                            realmUser.configure(with: user, in: realm)

                            try? realm.write {
                                realm.add(realmUser, update: true)
                            }

                            self!.setState(.authenticated)

                            observer.onNext(signinResult)

                        }, onError: { (error) in
                            observer.onError(error)
                        }, onCompleted: {
                            observer.onCompleted()
                        }).subscribe()

                    }, onError: { error in
                        observer.onError(error)
                }, onCompleted: {
                    print("completed")
                    observer.onCompleted()
                }).subscribe()

            return Disposables.create()
        }

我知道这是不对的,因为当两个动作完成时,我无法使用signin结果发送onNext信号。我一直在阅读,我发现我需要对两个动作进行平面映射,将它们组合成一个信号,然后操纵signinresult,但我不知道如何做到这一点。所以任何帮助都会很好。

谢谢

编辑1:

所以我重构代码看起来像这样,但是仍然存在一个问题,即当BOTH操作完成时我无法发送信号,或者我错了?

func signIn(signinParameters: SignInParameters) -> Observable<SignInResult> {
    return Observable<SignInResult>.create { [unowned self] observer in
        self.signinParameters = signinParameters

    self.apiConnector
        .signIn(with: signinParameters)
        .do(onNext: { (result) in

        }, onError: { (error) in

        }, onCompleted: { 

        })
        .flatMap({ (result) -> Observable<User> in
            self.apiConnector.get().asObservable()
        })
        .do(onNext: { (user) in

        }, onError: { (error) in

        }, onCompleted: { 

        }).subscribe()

        return Disposables.create()
    }
}

1 个答案:

答案 0 :(得分:1)

你的代码不是很干净,很难理解发生了什么(我的意见)。

如果您需要执行两个操作,则可以创建两个函数:

struct Parameters{}
struct Profile{}
struct User{}

func login(parameters: Parameters) -> Observable<User> {
    // get user
}

func profile(user: User) -> Observable<Profile> {
    // get profile
}

func serial(parameters: Parameters) -> Observable<Profile> {
    return login(parameters: parameters).flatMap({ profile(user: $0) })
}
如果需要,

login函数或profile函数也可以拆分为更小的函数:

func profileStored(user: User) -> Observable<Profile?> {
    // get stored profile
}

func profileRequested(user: User) -> Observable<Profile> {
    // get profile from network
}

func profile(user: User) -> Observable<Profile> {
    let observable = profileStored(user: user)
        .shareReplayLatestWhileConnected()
    let observableStored = observable
        .filter({ $0 != nil })
        .map({ $0! })
        .shareReplayLatestWhileConnected()
    let observableRequested = observable
        .filter({ $0 == nil })
        .flatMap({ _ in profileRequested(user: user) })
        .shareReplayLatestWhileConnected()
    return Observable
        .of(observableStored, observableRequested)
        .merge()
        .shareReplayLatestWhileConnected()
}

因此,您可以将较小的函数与flatMap或任何其他运算符混合使用。

这就是我的方式。希望它会有所帮助