2016-04-28 20 views
6

現在、Moyaを使用してネットワークリクエストを行っています。私は例プロジェクトの1つから以下を実装しました@https://github.com/DroidsOnRoids/RxSwiftExamples#tutorialsテーブルビュー(Moya、RxSwift、RxCocoa)へのバインドと組み合わせたネットワークエラーの処理

以下私は誰かがテキストを入力したときに新しい要求をするようにrestaurantSearchを設定しました。

var restaurantSearch: Observable<(String)> { 
    return searchBar 
     .rx_text 
     .throttle(0.5, scheduler: MainScheduler.instance) 
     .distinctUntilChanged() 
} 

私は種類の観測可能を返すメソッド[レストラン]

func restaurants() -> Observable<[Restaurant]> { 
    return restaurantSearch 
     .observeOn(MainScheduler.instance) 
     .flatMapLatest { postcode -> Observable<[Restaurant]?> in 
      return self.getRestaurants(postcode, cuisine: "", restaurantName: "") 
     }.replaceNilWith([]) 
} 

internal func getRestaurants(postcode: String, cuisine: String, restaurantName: String) -> Observable<[Restaurant]?> { 
    return self.justEatProvider 
     .request(.Restaurant(postcode, cuisine, restaurantName)) 
     .debug() 
     .mapArrayOptional(Restaurant.self, keyPath: "Restaurants") 
} 

を持っている私は、このメソッドを呼び出して、そのようにtableViewにバインドしています:

func setupRx() { 

    api = JustEatApi(provider: provider, restaurantSearch: restaurantSearch) 

    api 
     .restaurants() 
     .bindTo(tableView.rx_itemsWithCellIdentifier("RestaurantTableViewCell", cellType: RestaurantTableViewCell.self)) { (row, element, cell) in 
      cell.restaurant = element 
     } 
     .addDisposableTo(disposeBag) 
} 

ですうまく動作します。郵便番号を入力すると、検索が実行され、tableViewが読み込まれます。

インターネットをオフにして郵便番号を変更しようとすると、tableViewはそのままです。私はスクロールするときしかし、それは次のように私のアプリをクラッシュ:

@noreturn func rxFatalError(lastMessage: String) { 
    // The temptation to comment this line is great, but please don't, it's for your own good. The choice is yours. 
    fatalError(lastMessage) 
} 

また、私はスクロールではなく、単にインターネット上で引き返すと、何も起こりません郵便番号を変更しない場合。それはそれが拘束力を失ったようだ。

は、まず私がbindToメソッド呼び出しの前にcatchOnErrorを追加しようとしたが、私はそれがUIBindingの一部として扱われるべきでないことを、ここでコメントで読み:http://blog.scottlogic.com/2014/05/11/reactivecocoa-tableview-binding.html

私はこの方法でそれを処理する必要があります推測しています:

func restaurants() -> Observable<[Restaurant]> { 
    return restaurantSearch 
     .observeOn(MainScheduler.instance) 
     .flatMapLatest { postcode -> Observable<[Restaurant]?> in 
      return self.getRestaurants(postcode, cuisine: "", restaurantName: "") 
     }.replaceNilWith([]) 
} 

だから私は2つの質問があります。

1)どこで、どのように私はネットワークエラーを処理する必要がありますか?

2)インターネットに戻った後にtableViewが更新されないのはなぜですか?

ご迷惑をおかけして申し訳ございません。

答えて

8

私は、ネットワークリクエストを作成/解析するサービスでネットワークエラーを個人的に処理します。良い方法は、あなたのネットワーク結果を何らかの種類の列挙型でラップすることです(オプションの場合と同様ですが、nilの場合はエラーが発生します)。だからあなたのようなものだろう:

enum APIResult<T> { 
    case Success(T) 
    case Error(ErrorType) 
} 

をしてからサービスを使用すると、MVVMアーキテクチャを使用する場合は、ビューモデルにのみ成功した結果をフィルタリングし、にそのデータを提供することになる。この

Observable<APIResult<[Restaurant]>> 

のようなものを返しますビューコントローラ。

ドライバもご覧ください。 UIバインディングのために特別に作られたユニットなので、メインスレッドだけに登録し、エラーは発生せず、最後の結果を共有します。

次の3つの方法のいずれかを使用ドライバーに観察可能な変換するために:観察可能でエラーを発したときに、すべての加入者は、すなわち、退会ので

func asDriver(onErrorJustReturn onErrorJustReturn: Self.E) -> RxCocoa.Driver<Self.E> 
func asDriver(onErrorDriveWith onErrorDriveWith: RxCocoa.Driver<Self.E>) -> RxCocoa.Driver<Self.E> 
func asDriver(onErrorRecover onErrorRecover: (error: ErrorType) -> RxCocoa.Driver<Self.E>) -> RxCocoa.Driver<Self.E> 

このアプローチは、自動的に、あなたの2番目の質問に対処します。ストリームを終了します。 .debug()をあなたのapi.restaurants()の後ろに置いてみて、それを解除してください。

ドライバーとその他のユニットについて詳しく読むことができますhere

+0

ニース!個人的に私がビューモデルを使用しているとき、私はビューモデルでこの変数を持っているので、コントローラはエラーを知らせます。コントローラはそれを独立したユニットとして聴くことができます。それ以外の 'APIResult'は素晴らしいですが、あなたは[Result](https://github.com/antitypical/Result)を使うこともできます。 – sunshinejr

関連する問題