10

現在、Moya を使用してネットワーク リクエストを行っています。サンプル プロジェクト @ https://github.com/DroidsOnRoids/RxSwiftExamples#tutorialsの 1 つから以下を実装しました。

以下では、誰かがテキストを入力すると新しいリクエストが作成されるように、restaurantSearch をセットアップしました。

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

タイプ [Restaurant] のオブザーバブルを返すメソッドがあります。

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

また、スクロールせずにインターネットに戻って郵便番号を変更しても、何も起こりません。拘束力を失ったようです。

まず、メソッド呼び出しの前に catchOnError を追加しようとしましbindToたが、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 が更新されないのはなぜですか?

どんな助けでも大歓迎です。

4

2 に答える 2

11

私は、ネットワーク リクエストを作成/解析するサービスのネットワーク エラーを個人的に処理します。これを行う良い方法は、ネットワークの結果をある種の列挙型でラップすることです (オプションに似ていますが、nil の場合はエラーになります)。したがって、次のようなものになります。

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

そして、あなたのサービスはこのようなものを返します

Observable<APIResult<[Restaurant]>>

MVVM アーキテクチャを使用する場合は、ビュー モデルで成功した結果のみをフィルター処理し、そのデータをビュー コントローラーに提供します。

また、ドライバーユニットもご覧ください。これは UI バインディング用に特別に作成されたユニットであるため、メイン スレッドのみでサブスクライブし、エラーが発生せず、最後の結果を共有します。

Observable を Driver に変換するには、次の 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>

Observable がエラーを発行すると、すべてのサブスクライバーがサブスクライブを解除するため、このアプローチは自動的に 2 番目の質問に対処します。ストリームを終了します。api.restaurants()呼び出しの背後に .debug() を配置して、サブスクライブが解除されることを自分で確認してください。

ドライバーとその他のユニットの詳細については、こちらをご覧ください。

于 2016-05-11T19:47:23.603 に答える