ReactiveCocoa 4 - 创建仅运行一次的依赖登录请求

时间:2016-02-03 04:48:50

标签: reactive-cocoa reactive-cocoa-4

过去我主要使用ReactiveCocoa来简单地绑定视图和查看模型,现在我试图在整个新项目中尝试使用它但我遇到了麻烦让我的头围绕几件事。

我想做的就是这个 -

  • 有一个网络登录请求,其他所有网络请求都需要先调用。
  • 如果有多个请求,他们都需要等到登录完成后(例如,让我们说我有一个标签栏控制器,我会在登录完成之前快速点击它们;我不知道#39;想要多次登录请求。)

我花了一些时间探索像队列这样的选项,研究flatMap(.Latest)这样的事情,但如果我完全诚实 - 我不知道我在做什么! :S

以下是一个非常基本的,愚蠢的实现,很快被黑客攻击,很可能很难实现。如果有人能给我一些指示我需要改变的东西,我将非常感激。我的doSomething方法显然首先登录,但如果一次拨打多个电话,他们就不会等到第一个电话完成,因为我需要它们。

我可以使用loginValid属性做点什么吗?

(另外,关于我应该如何构建这些东西的指针会很棒 - 我确定我用这段代码做了许多愚蠢的事情)

谢谢!

class FakeBackend: BackendType {

    private var loginResponse = MutableProperty<LoginResponse?>(nil)
    private let loginValid = MutableProperty<Bool>(false)

    private var loginProducer: SignalProducer<LoginResponse, NSError>! // <-- implicitly unwrapped optional? Yuck

    init() {
        loginValid <~ loginResponse.producer.map { $0 != nil }

        loginProducer = SignalProducer { [weak self] observer, disposable in
            guard let _self = self else { return }

            if let loginResponse = _self.loginResponse.value {
                print("Already have login details")
                observer.sendNext(loginResponse)
                observer.sendCompleted()
            } else {
                print("Don't have login details, go get them")
                _self.logIn().start(observer)
            }
        }
    }

    func doSomething() -> SignalProducer<HomeResponse, NSError> {
        return loginProducer
            .then(SignalProducer<HomeResponse, NSError> { observer, dispoable in

                let homeResponse = HomeResponse(title: "My title is this")

                observer.sendNext(homeResponse)
                observer.sendCompleted()
            })
    }

    private func logIn() -> SignalProducer<LoginResponse, NSError> {
        return SignalProducer { observer, disposable in

            print("Calling network login")
            delayToMainThread(1.0, closure: { [weak self] () -> () in

                guard let _self = self else { return }

                let loginResponse = LoginResponse(accessToken: "MyAccessToken")

                _self.loginResponse.value = loginResponse

                observer.sendNext(loginResponse)
                observer.sendCompleted()
            })
        }
    }
}

1 个答案:

答案 0 :(得分:0)

执行此操作的正确方法是replayLazilyhttps://github.com/ReactiveCocoa/ReactiveCocoa/issues/2706

  

-replayLazily方便方法返回一个新的信号,当时   订阅后,将立即向订户发送整个历史记录   通过源信号的值,没有   重新执行源信号的订阅代码。

我收到了关于ReactiveCocoa Github问题页面的问题的回复。 {{3}}

基本上,你想做这样的事情 -

class FakeBackend: BackendType {

    private var login: SignalProducer<LoginResponse, NSError>

    init() {
        login = SignalProducer { observer, disposable in
            print("Logging in...")

            // we'd actually make a network call here, but for demo purposes
            // let's just return some dummy data.
            let loginResponse = LoginResponse(accessToken: "MyAccessToken")

            print("Logged in!")

            observer.sendNext(loginResponse)
            observer.sendCompleted()
        }.replayLazily(1)
    }

    func loadHomeScreen() -> SignalProducer<HomeResponse, NSError> {
        return login
            .flatMap(.Latest, transform: homeResponse)
    }

    private func homeResponse(loginResponse: LoginResponse) -> SignalProducer<HomeResponse, NSError> {
        return SignalProducer<HomeResponse, NSError> { observer, disposable in
            print("Aaaand, we've gotten our HomeResponse.")

            let homeResponse = HomeResponse(title: "My title is this")
            observer.sendNext(homeResponse)
            observer.sendCompleted()
        }
    }
}