如何在核心数据上创建可观察对象并将其绑定到 tableView
How do I create an observable on core data and bind it to tableView
我这样获取 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)
这看起来合理吗,还是有其他方法?
Rx 在处理数据流时特别有用,但您正试图将其用作围绕单个核心数据获取请求的简单包装器。我会构建一个 BehaviorRelay
来保留来自 Core Data 的数据副本,以及一个 Observable 来运行您的获取请求并将值报告给 BehaviorRelay
,您可以在需要时随时订阅刷新。
在您的视图模型中:
let data = BehaviorRelay<[MyDataObject]>(value: [])
我会将其绑定到您的 table 视图:
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
发出的值立即更改您的 UI,例如显示空白屏幕或停止加载指示器。如果这样做,请确保在订阅前添加 observeOn(MainScheduler.instance)
。
让我们从您的提取开始。
func fetchAllData() -> Observable<[MyDataObject]> {
Observable.just(coreData.fetchAll(fetchRequest: NSFetchRequest<MyDataObject>(entityName: "MyDataObject")))
}
(以上与您的 fetchAllData 所做的相同,但更简洁。)
现在想一想您可能想要获取数据的所有原因...假设您有一个刷新按钮,并且您唯一想要获取所有数据的时间是用户点击该按钮时。然后在您的 viewDidLoad
(或从它调用的函数中)中,您将拥有:
let allData = refreshButton.rx.tap
.flatMap {
fetchAllData()
}
假设我们要在 table 视图上显示数据。我们想要在视图上重新加载数据的所有原因是什么?假设我们想要重新加载数据的唯一原因是 allData
发出一个值。然后也在 viewDidLoad
(或从中调用的函数)中,您将拥有:
allData
.bind(to: tableView.rx.items(cellIdentifier: Cell.identifier, cellType: Cell.self)) { row, data, cell in
cell.viewModel = data
}
.disposed(by: disposeBag)
好了,就这么简单。
当然,当您设想其他时候您可能想要获取所有数据时,事情会变得更加复杂,但以上是基础知识。
我这样获取 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)
这看起来合理吗,还是有其他方法?
Rx 在处理数据流时特别有用,但您正试图将其用作围绕单个核心数据获取请求的简单包装器。我会构建一个 BehaviorRelay
来保留来自 Core Data 的数据副本,以及一个 Observable 来运行您的获取请求并将值报告给 BehaviorRelay
,您可以在需要时随时订阅刷新。
在您的视图模型中:
let data = BehaviorRelay<[MyDataObject]>(value: [])
我会将其绑定到您的 table 视图:
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
发出的值立即更改您的 UI,例如显示空白屏幕或停止加载指示器。如果这样做,请确保在订阅前添加 observeOn(MainScheduler.instance)
。
让我们从您的提取开始。
func fetchAllData() -> Observable<[MyDataObject]> {
Observable.just(coreData.fetchAll(fetchRequest: NSFetchRequest<MyDataObject>(entityName: "MyDataObject")))
}
(以上与您的 fetchAllData 所做的相同,但更简洁。)
现在想一想您可能想要获取数据的所有原因...假设您有一个刷新按钮,并且您唯一想要获取所有数据的时间是用户点击该按钮时。然后在您的 viewDidLoad
(或从它调用的函数中)中,您将拥有:
let allData = refreshButton.rx.tap
.flatMap {
fetchAllData()
}
假设我们要在 table 视图上显示数据。我们想要在视图上重新加载数据的所有原因是什么?假设我们想要重新加载数据的唯一原因是 allData
发出一个值。然后也在 viewDidLoad
(或从中调用的函数)中,您将拥有:
allData
.bind(to: tableView.rx.items(cellIdentifier: Cell.identifier, cellType: Cell.self)) { row, data, cell in
cell.viewModel = data
}
.disposed(by: disposeBag)
好了,就这么简单。
当然,当您设想其他时候您可能想要获取所有数据时,事情会变得更加复杂,但以上是基础知识。