使用RxSwift进行异步API调用后更新视图

时间:2017-02-27 11:59:50

标签: swift realm rx-swift

我正在尝试使用MVVM模式将RxSwift添加到代码中。我的应用程序需要从API获取FoodType(沙漠,餐等)列表并将其保存到Realm数据库。然后,我有一个UITextField和UIButton的视图。

用户写食物类型(例如:沙漠):

  • 背景:如果不是在Realm DB中,应用程序应该从Api获取FoodType和FoodList
  • 点击按钮:显示用户从Realm
  • 中选择FoodType的Food列表

视图模型

struct FoodTypeViewModel { 

    // Get datas from API   
    private func getFoods() {
        foodService.getAll(completionHandler: { result in
            switch result {
            case .Success(let foods):
                for food in foods {
                    food.save()
                }
                break
            case .Failure(let error):
                debugPrint(error)
                break
            }
        })
    }

    // Get datas from API   
    private func getFoodTypes() {
        foodService.getAll(completionHandler: { result in
            switch result {
            case .Success(let foodTypes):
                for type in types {
                    type.save()
                }
                break
            case .Failure(let error):
                debugPrint(error)
                break
            }
        })
    }
}

的ViewController

class SetupViewController: UIViewController {
        @IBOutlet weak var foodTypeTextField: UITextField!
        @IBOutlet weak var foodTypeButton: UIButton!
}

模型

class FoodType: Object {
    dynamic var identifier: String = ""
    dynamic var fullName: String?
    let foods = List<Food>()
}

我想将RxSwift添加到该代码中,但我该如何处理异步API。首次启动时,应用程序没有数据(我不想在开始时填充)但是当用户单击按钮时。因此,在按钮单击时,UI应等待来自服务的响应(使用等待动画),并且ViewModel应在服务响应时更新UI。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

首先,创建一个通用的返回对象来包装通信错误。

enum APIResult<T> {
    case success(T)
    case error(Error)
}

然后,转换完成处理程序以返回Observable

func getFoods() -> Observable<APIResult<[FoodType]>> {
    return Observable<APIResult<[FoodType]>>.create { observer -> Disposable in
        self.foodService.getAll(completionHandler: { result in
            switch result {
            case .Success(let foods):
                observer.onNext(.success(foods))
                break
            case .Failure(let error):
                observer.onNext(.error(error))
                break
            }
            observer.onCompleted()

            return Disposables.create()
        })
    }
}

现在只需像在RxSwift中一样处理observable。

getFoods().subscribe(onNext: { result in
    switch result {
        case .success(let foods):
            print("Received foods: \(foods)")
            break
        case .error(let error):
            print("Received error: \(error)")
            break
    }
}.addDisposableTo(disposeBag)

使用these utility classes将帮助您映射成功结果,并将错误和成功信号拆分到不同的可观察对象。例如:

let foodsRequest = getFoods().splitSuccess

foodsRequest.error.subscribe(onNext: { error in
    print("Received error: \(error)")
})

foodsRequest.success.subscribe(onNext: { foods in
    print("Received foods: \(foods)")
}

您还可以将Realm对象转换为RxSwift observables:

let realm = try! Realm()
realm.objects(Lap).asObservable()
  .subscribeNext {[weak self] laps in
    self?.tableView.reloadData()
  }

请查看Using Realm Seamlessly in an RxSwift App以获取更多信息和示例。