2016-05-27 3 views
4

Я хочу запустить задачу входа в систему, нажав кнопку входа в систему, после этого выберете список заказов пользователя, адрес доставки, список пожеланий, другую информацию. startTask - кнопка, пользователь нажимает ее, я запускаю эти задачи, но теперь, если ошибка входа в систему, пользователь снова коснитесь кнопки StartTask, я не могу снова запустить эти задачи, почему?
Пример кодаЗадача RxSwift async

private func test() { 

    let data = ["fetch order list", "fetch shipping addresses", "fetch wishlist", "fetch other info"] 

    let fetchInfoTasks = data.map{ asyncTask($0) }.toObservable() 
    let someTasks = fetchInfoTasks.merge().toArray() 
    let result = login().flatMapLatest{ _ in someTasks } 

    startTask 
     .rx_tap 
     .flatMapLatest{ result } 
     .catchError{ error in 
      .....error...... 
      return Observable.empty() 
     } 
     .subscribeNext{ tasks in 
      .....all completed.... 
     } 
     .addDisposableTo(disposeBag) 
} 

private func login()-> Observable<String> { 
    return Observable.create{ observer in 
     performClosure(afterDealy: 1, onMainQueue: false) { 
      if arc4random() % 4 == 0 { 
       observer.onNext("login finished") 
       observer.onCompleted() 
      } else { 
       observer.onError(NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "some error"])) 
      } 
     } 
     return AnonymousDisposable{} 
    } 
} 

private func asyncTask(name: String)-> Observable<String> { 
    return Observable.create{ observer in 
     let delay = Double(arc4random() % 6 + 1) 
     performClosure(afterDealy: delay, onMainQueue: false) { 
      observer.onNext(name) 
      observer.onCompleted() 
     } 
     return AnonymousDisposable{} 
    } 
} 

func performClosure(afterDealy delay: Double, onMainQueue mainQueueOrNot: Bool, action: dispatch_block_t) { 
    let delayIntervals = Double(NSEC_PER_SEC) * delay 
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delayIntervals)) 
    let queue = mainQueueOrNot ? dispatch_get_main_queue() : dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) 
    dispatch_after(time, queue, action) 
} 

ответ

3

После того, как происходит ошибка, то поток завершается. Вы не хотите, чтобы это происходило на уровне вашей кнопки, поэтому вы должны ловить ошибки на более глубоком уровне.

Например:

startTask 
    .rx_tap 
    .flatMapLatest{ 
     result 
      .catchError{ error in 
       .....error...... 
       return Observable.empty() 
      } 
    } 
    .subscribeNext{ tasks in 
     .....all completed.... 
    } 
    .addDisposableTo(disposeBag) 

Таким образом, вы можете предотвратить фактическую ошибку Rx из бурлит через flatMap.

Если вам нужно что-то сделать с ошибкой, вы, вероятно, захотите обернуть свой результат каким-то результатом перечисления результатов (рекомендуется https://github.com/antitypical/Result).

Примером этого может быть:

startTask 
    .rx_tap 
    .flatMapLatest{ 
     result 
      .map { Result.Success(result: $0) 
      .catchError{ error in return Result.Error(error: $0) } 
    } 
    .subscribeNext{ result in 
     switch(result) { 
      case .Success(let result): 
       //display happy case 
      case .Error(let error): 
       //display sad case 
    } 
    .addDisposableTo(disposeBag) 
+0

После возникновения ошибки, поток завершается. Спасибо, это очень полезно! Могу ли я спросить, есть ли какие-либо источники/примеры, из которых я могу найти связанные с ними практики RxSwift (кроме документации)? –

2

Как указано в catchError документации:

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

Таким образом, при возникновении ошибки в цепочке входа в систему ошибка попадает в замыкание catchError, и последовательность завершается.

Вот пример вывода о том, что происходит:

2016-05-27 10:03:18.634: AppDelegate.swift:59 (test()) -> subscribed 
2016-05-27 10:03:19.792: AppDelegate.swift:59 (test()) -> Event Error(Error Domain= ...ription=some error}) 
2016-05-27 10:03:19.796: AppDelegate.swift:59 (test()) -> disposed 

То, что работало для меня в подобных случаях, чтобы переместить catchError обработчик внутри затвора, который фактически делает некоторую работу (например, запрос выполнения сети) и вернуть какой-то Result перечисление для обработки ошибки в subscribeNext.

Вот скорректированный test() функция, которая использует технику, которую я описал

enum Result<T> 
{ 
    case Success(value: T) 
    case Failure(error: ErrorType) 
} 

private func test() { 

    let data = ["fetch order list", "fetch shipping addresses", "fetch wishlist", "fetch other info"] 

    let fetchInfoTasks = data.map{ asyncTask($0) }.toObservable() 
    let someTasks = fetchInfoTasks.merge().toArray() 
    let result = login().flatMapLatest{ _ in someTasks } 


    let resultHandled = result.map{ Result.Success(value: $0) } 
           .catchError { .just(Result.Failure(error: $0)) } 


    let startTask = Observable<Int>.timer(0, period: 5, scheduler: MainScheduler.instance); 

    startTask 
     .flatMapLatest{ _ in resultHandled } 
     .debug() 
     .subscribeNext{ (result) in 
      print("\(result)") 
     } 
     .addDisposableTo(disposeBag) 
} 

И выход:

2016-05-27 10:07:25.507: AppDelegate.swift:59 (test()) -> subscribed 

2016-05-27 10:07:26.614: AppDelegate.swift:59 (test()) -> Event Next(Failure(Error D...iption=some error})) 
Failure(Error Domain= Code=-1 "some error" UserInfo={NSLocalizedDescription=some error}) 

2016-05-27 10:07:34.878: AppDelegate.swift:59 (test()) -> Event Next(Success(["fetch...ipping addresses"])) 
Success(["fetch wishlist", "fetch order list", "fetch other info", "fetch shipping addresses"]) 

2016-05-27 10:07:41.603: AppDelegate.swift:59 (test()) -> Event Next(Failure(Error D...iption=some error})) 
Failure(Error Domain= Code=-1 "some error" UserInfo={NSLocalizedDescription=some error}) 

2016-05-27 10:07:46.588: AppDelegate.swift:59 (test()) -> Event Next(Failure(Error D...iption=some error})) 
Failure(Error Domain= Code=-1 "some error" UserInfo={NSLocalizedDescription=some error}) 

Так как вы можете видеть, главную последовательность (в моем случае это таймер, в вашей последовательности событий нажатия кнопок) не выдается ошибка, и вы можете обрабатывать результат в subscribeNext. Надеюсь, это поможет!

UPD

Here're некоторые ресурсы, которые могут оказаться полезными:

  1. https://github.com/ReactiveX/RxSwift/tree/master/RxExample
  2. http://rx-marin.com/
  3. https://github.com/artsy/eidolon
  4. https://realm.io/news/ - у них есть несколько переговоров по RxSwift
  5. https://gist.github.com/JaviLorbada/4a7bd6129275ebefd5a6 - список FRP ресурсов
  6. http://slack.rxswift.org/ - всемогущий RxSwift членов сообщества :)
+0

Спасибо, это очень полезно! Могу ли я спросить, есть ли какие-либо источники/примеры, из которых я могу найти связанные с ними практики RxSwift (кроме документации)? –

+0

, пожалуйста, просмотрите мои обновления для краткого списка ресурсов, которые могут быть полезны – NikGreen

Смежные вопросы