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

Update view after async API call with RxSwift

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

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

ViewModel

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。有什么想法吗?

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

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

然后,将完成处理程序转换为 return 和 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 中的任何其他对象一样处理可观察对象。

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 可观察对象:

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

查看 Using Realm Seamlessly in an RxSwift App 了解更多信息和示例。