2016-04-28 151 views
6

我目前正在使用Moya来提出我的网络请求。我已经实施了以下示例项目之一@https://github.com/DroidsOnRoids/RxSwiftExamples#tutorials处理网络错误与绑定到tableView(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

我个人处理网络请求的服务中的网络错误。这样做的好方法是将网络结果包装在某种枚举中(类似于可选,但如果为零,则会出错)。所以,你会碰到这样的:

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

,然后如果你使用MVVM架构那么你就只过滤在视图模型成功的结果和数据提供给你的服务会回到这样的事情

Observable<APIResult<[Restaurant]>> 

视图控制器。

另外你应该看看司机单位。它是专门用于UI绑定的单元,因此它仅在主线程上订阅,从不出错并共享最后的结果。

要转换可观察到的驱动程序在使用这三种方法之一:

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> 

这种方法将你的第二个问题自动处理,因为当可观察发出错误,所有订户退订,即。它终止流。尝试将.debug()放在您的api.restaurants()调用后面,然后自己看看它是否取消订阅。

你可以阅读更多关于Driver等单位here

+0

尼斯之一!就我个人而言,当我使用视图模型时,我也在视图模型中使用了这个变量来通知有关错误,因此控制器可以将它作为一个独立单元进行监听。除此之外'APIResult'很棒,你也可以使用[Result](https://github.com/antitypical/Result)。 – sunshinejr