如何在核心数据上创建可观察对象并将其绑定到 tableView

Posted

技术标签:

【中文标题】如何在核心数据上创建可观察对象并将其绑定到 tableView【英文标题】:How do I create an observable on core data and bind it to tableView 【发布时间】:2020-04-27 14:04:04 【问题描述】:

我这样获取core data

var persistingData: [MyDataObject] = coreData.fetchAll(fetchRequest: NSFetchRequest<MyDataObject>(entityName: "MyDataObject"))

现在我该如何着手将这些数据用于Observable,它可以将bind 数据用于rx tableView

我是否像这样创建observable

func fetchAllData() -> Observable<[MyDataObject]> 
    var persistingData: [MyDataObject] = coreData.fetchAll(fetchRequest: NSFetchRequest<MyDataObject>(entityName: "MyDataObject"))

    return Observable.create( observable in
        observable.onNext(persistingData)
        observable.onCompleted()
        return Disposables.create()
    )

但是如果我将数据传递给onNext,我如何在observable 上使用bind()bind 直接在method 上使用,如下所示:

fetchAllData().bind()

我如何真正将data 放入observable 以便它可以在bind() 中使用?

编辑

我也试过这样。这是一种有效的方法吗?

func fetchAllData() -> PublishRelay<[MyDataObject]> 
    var persistingData: [MyDataObject] = coreData.fetchAll(fetchRequest: NSFetchRequest<MyDataObject>(entityName: "MyDataObject"))

    let relay = PublishRelay<[LocalDoorCoreDataObject]>()
    relay.accept(persistingDoors)
    return relay

然后你可以像这样bind它:

viewModel.fetchAllData().bind(to: tableView.rx.items(cellIdentifier: Cell.identifier, cellType: Cell.self))  row, data, cell in

    cell.viewModel = data

.disposed(by: disposeBag)

这看起来合理吗,还是有其他方法?

【问题讨论】:

【参考方案1】:

Rx 在处理数据流时特别有用,但您正试图将其用作单个核心数据获取请求的简单包装器。我会构建一个BehaviorRelay 来保留来自Core Data 的数据的副本,以及一个运行您的获取请求并将值报告给BehaviorRelay 的Observable,您可以在需要刷新时随时订阅。

在您的视图模型中:

let data = BehaviorRelay<[MyDataObject]>(value: [])

我会将它绑定到您的表格视图:

viewModel.data.bind(to: tableView.rx.items(cellIdentifier: Cell.identifier, cellType: Cell.self))  row, data, cell in
    cell.viewModel = data

.disposed(by: disposeBag)

然后,回到你的视图模型:

var loadData: Observable<[MyDataObject]> 
   return Observable.deferred  [unowned self] in
      return Observable.just(self.coreData.fetchAll(fetchRequest: NSFetchRequest<MyDataObject>(entityName: "MyDataObject")))
   .do(onNext:  [unowned self] data in
      self.data.accept(data)
   

任何时候你需要刷新数据,你只需调用:

viewModel.loadData.subscribe().disposed(by: disposeBag)

您可以使用loadData 发出的值立即更改您的用户界面,例如显示空白屏幕或停止加载指示器。如果有,请务必在订阅前添加observeOn(MainScheduler.instance)

【讨论】:

【参考方案2】:

让我们从您的抓取开始。

func fetchAllData() -> Observable<[MyDataObject]> 
    Observable.just(coreData.fetchAll(fetchRequest: NSFetchRequest<MyDataObject>(entityName: "MyDataObject")))

(上面的内容与您的 fetchAllData 所做的相同,但更简洁。)

现在想想您可能想要获取数据的所有原因...假设您有一个刷新按钮,并且您想要获取所有数据的唯一时间是用户点击该按钮时。然后在您的 viewDidLoad (或从它调用的函数中)中,您将拥有:

let allData = refreshButton.rx.tap 
    .flatMap  
        fetchAllData()
    

假设我们想在表格视图上显示数据。我们想要在视图上重新加载数据的所有原因是什么?假设我们想要重新加载数据的唯一原因是allData 发出一个值。然后在viewDidLoad(或从中调用的函数)中,您将拥有:

allData
    .bind(to: tableView.rx.items(cellIdentifier: Cell.identifier, cellType: Cell.self))  row, data, cell in
        cell.viewModel = data
    
    .disposed(by: disposeBag)

就这么简单。

当然,当您设想其他时候您可能想要获取所有数据时,事情会变得更加复杂,但以上是基础知识。

【讨论】:

以上是关于如何在核心数据上创建可观察对象并将其绑定到 tableView的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SwiftUI 中使用可观察对象并与 NavigationLink 绑定?

刷新 WPF Datagrid 未绑定到可观察集合?

如何将图像源绑定到 ngFor 循环内的可观察对象?

knockoutjs 可观察对象绑定的可观察数组

如何将可观察对象发布的整数变量绑定到 SwiftUI 中的 textField?

从 txt 文件中读取数据并将其添加到 Observable 集合中