【问题标题】:Handling Network error in combination with binding to tableView (Moya, RxSwift, RxCocoa)结合绑定到 tableView (Moya, RxSwift, RxCocoa) 处理网络错误
【发布时间】:2016-08-23 21:04:39
【问题描述】:

我目前正在使用 Moya 发出我的网络请求。我已经从示例项目之一 @https://github.com/DroidsOnRoids/RxSwiftExamples#tutorials

中实现了以下内容

我在下面设置了 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)
}

另外,如果我不滚动而只是重新打开互联网并更改邮政编码,则不会发生任何事情。它似乎失去了它的约束力。

首先我尝试在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([])
}

所以我有两个问题:

1) 我应该在哪里以及如何处理网络错误?

2) 为什么我重新上网后tableView没有更新?

非常感谢任何帮助。

【问题讨论】:

    标签: swift uitableview rx-swift moya


    【解决方案1】:

    只需在绑定表之前添加 catchErrorJustReturn([])

    【讨论】:

      【解决方案2】:

      我亲自处理发出/解析网络请求的服务中的网络错误。这样做的好方法是将您的网络结果包装在某种枚举中(类似于可选,但如果为零则错误)。所以你会有类似的东西:

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

      然后你的服务会返回类似这样的东西

      Observable<APIResult<[Restaurant]>>
      

      如果您使用 MVVM 架构,那么您将只过滤视图模型中的成功结果并将该数据提供给视图控制器。

      你还应该看看 Driver 单元。它是专门为 UI 绑定而设计的单元,因此它仅在主线程上订阅,从不出错并共享最后的结果。

      要将 Observable 转换为 Driver,您可以使用以下三种方法之一:

      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 发出错误时,所有订阅者都会取消订阅,即。它终止流。尝试将 .debug() 放在您的 api.restaurants() 调用之后,然后自己查看它是否取消订阅。

      你可以阅读更多关于司机和其他单位here

      【讨论】:

      • 不错的一个!就我个人而言,当我使用视图模型时,我在视图模型中也有这个变量来通知错误,因此控制器可以将它作为一个独立的单元来监听。除了APIResult 很棒,你也可以使用Result
      猜你喜欢
      • 1970-01-01
      • 2017-01-12
      • 2019-03-17
      • 2023-03-12
      • 1970-01-01
      • 2019-03-18
      • 2018-04-09
      • 1970-01-01
      • 2016-03-14
      相关资源
      最近更新 更多