swift - 使用 RxSwift 调用异步 API 后更新 View

标签 swift realm rx-swift

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

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

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

View 模型

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

View Controller

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

最佳答案

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

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 中的任何其他对象一样处理可观察对象。

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获取更多信息和示例。

关于swift - 使用 RxSwift 调用异步 API 后更新 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42485275/

相关文章:

ios - 如何将数据从 UIViewController 发送到 UITabBarControllers swift ios 中的第一个选项卡

ios - UITextView InputView UITableViewController

swift - REALM 原因 : 'Attempting to modify object outside of a write transaction - call beginWriteTransaction on an RLMRealm instance first.'

ios - 如何检测状态栏 iOS 13 上的触摸

ios - 将 PNG 附加到 MFMailComposer 时,图像会自动旋转为横向

java - 在 Android 上更新 Realm.io 数据库表中所有行的最佳方法是什么?

ios - Swift - 通过 UICollectionView 中的 UISearchBar 过滤 Realm 对象

swift - RxSwift 异步任务

swift - UIViewController 不取消初始化(mvvm + 协调器)

swift - RxSwift - 映射后函数的调用顺序