这就是我最后做的。需要通过两种方式处理NSFetchedResultsController(NFRC) - 获取数据(即执行查询)以及通过委托调用设置ManagedObject(MO)的更改通知。
获取数据不会触发委托调用。因此,您通常会返回运行获取的结果,即一个NFRC.fetchedObjects(),在工作者或交互器中重新打包为PONSOS,并将这些结果传递给Presenter以传递给ViewController。
我发现它更容易,就像使用DataSource委托作为ViewController一样(当Table View是实现的一部分时) - 我将它作为ViewController的单独类实现。
该方法保持标准的VIP循环,并且不需要视图层中的模型知识。
处理委托调用有点棘手。 NFRC通常绑定到View层以处理表视图数据委托请求:NFRC通知插入,删除,移动,更新更改,委托对其进行适当处理。然而,在一个不能发生的VIP体系结构中,因为NFRC无法附加到视图 - 它生活在模型层,需要留在那里。
我在存储实例实例化此并把存储实例的NFRC委托并实施了委托方法为:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
print("item changed")
guard let managedItem = anObject as? ManagedItem else {
return
}
let item = managedItem.toItem()
var eventType: EventType
switch type {
case .insert:
eventType = EventType.insert
case .delete:
eventType = EventType.delete
case .move:
eventType = EventType.move
case .update:
eventType = EventType.update
}
let itemChangeEvent = ItemChangeEvent(eventType: eventType, item: item, index: indexPath, newIndex: newIndexPath)
results.append(itemChangeEvent)
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
results = []
print ("Begin update")
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
print("End updates")
if let completionHandler = completion {
completionHandler(results)
}
}
基本上,我初始化空数组(开始更新),整理所有的通知作为事件对象(PONSOS)插入该数组(I,D,M,U),然后在完成时运行完成处理程序(结束更新)。完成处理程序作为fetch()操作的一部分传入并存储以供将来使用 - 即用于何时需要通知MO更改。 完成处理是通过从交互器过去了,看起来像:
func processFetchResults(itemChangeEvents: [ItemChangeEvent]) {
let response = ListItems.FetchItems.Response(itemEvents: itemChangeEvents)
presenter?.presentFetchedItems(response: response)
}
所以它传递的所有事件,其传递到数据源代表可以处理他们的演示。
但是这还不够。为了提高效率,Data Source委托人确实需要与NSFRC进行交互,以便将表视图行映射到正确索引路径中的数据行,处理部分信息等。因此,我所做的是创建一个名为DynamicDataSource的协议,实施由Interactor初始化的“包装”NSFRC并代理其方法。虽然模型技术上交给了View层,但它实际上被封装在一个协议后面,实现将MO转换为PONSOS。所以我将它看作Presenter图层的扩展(不是Swift扩展!)。
protocol ListItemsDynamicDataSource: AnyObject {
// MARK: - Helper methods
func numberOfSections() -> Int
func rowsInSection(_ section: Int) -> Int
func getItem(index: IndexPath) -> ListItems.FetchItems.ViewModel.DisplayedItem
}
如果持久性存储改变,比方说,一个内存中存储或JSON层,则动态数据源的实现可以妥善处理,没有影响观。显然这是使用NFRC的复杂方式,但我认为这是一个有用的类。对于一个简单的应用程序,它可能是矫枉过正。然而,它是有效的,我认为这是一个很好的,一致的妥协。
值得一提的是,我对Swift和IOS开发非常陌生,所以这可能不是世界上最好的代码,并且可能有更好的方法来实现它!我始终乐于接受反馈和改进建议。