2016-02-03 2 views
1

Я в основном использовал ReactiveCocoa в прошлом, чтобы просто привязывать представления и просматривать модели, и теперь я пытаюсь сделать решительный шаг и использовать его во всем новом проекте но у меня проблемы с головами вокруг нескольких вещей.ReactiveCocoa 4 - Создание зависимого запроса на вход, который запускается только один раз

То, что я хочу сделать это -

  • Есть запрос сетевого входа, другой запрос каждая сеть должна звонить первой.
  • Если выполнено несколько запросов, все они должны дождаться завершения регистрации (например, предположим, что у меня есть контроллер панели вкладок, и я быстро переключаюсь между ними до завершения регистрации, я не хочу, чтобы несколько запросов на вход . уволили)

Я потратил немного времени, исследуя несколько вариантов, таких как очереди, глядя на вещи, как 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() 
      }) 
     } 
    } 
} 

ответ

0

правильный способ сделать это через replayLazily, который описан в https://spin.atomicobject.com/2014/06/29/replay-replaylast-replaylazily/

Метод -replayLazily удобства возвращает новый сигнал, который, когда подписчики, немедленно отправить абоненту всю историю значений, которые прошли через исходный сигнал, без , повторно выполняющего код подписки на исходный сигнал.

Я получил ответ на свой вопрос на странице ReactiveCocoa Github Issues. https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2706

По сути, вы хотите сделать что-то вроде этого -

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