ad-*_*son 5 core-data ios swift viper-architecture clean-architecture
我已经在没有太多运气的情况下寻找了答案。这个问题几乎相同,但答案不是很清楚(至少对我来说!): 它是 VIPER 架构中 NSFetchedResultsController 的位置?
NSFetchedResultsController 对于 iOS 应用程序来说似乎是一种非常有用的方法,但是我所看到的所有示例都将其置于 ViewController 层——至少,VC 成为了一个委托。在 Clean Architecture/Viper 中,模型层与视图层非常脱节,我无法弄清楚 NSFRC 在这样的架构中是如何使用的。对上述问题的回答意味着交互器应该是一个委托,但这没有意义——然后托管对象将呈现给交互器,而不是 PONSO。也许我对它的理解还不够好,但是 (a) 它在 Clean Architecture 中占有一席之地吗?(b) 如果是,那么需要正确的 Swift 实现模式吗?
这就是我最后所做的。NSFetchedResultsController (NFRC) 需要通过两种方式进行处理 - 获取数据,即执行查询,以及通过委托调用通知 ManagedObject (MO) 集的更改。
获取数据不会触发委托调用。因此,您通常会返回运行 fetch 的结果,即 anNFRC.fetchedObjects(),在工作器或交互器中重新打包为 PONSOS,并将这些结果传递给 Presenter 以传递给 ViewController。
我发现使用 DataSource Delegate 作为 ViewController 更容易且更一致(当表视图是实现的一部分时) - 我将其实现为 ViewController 的单独类。
这种方法维护了标准的 VIP 周期,并且不需要视图层中的模型知识。
处理委托调用有点棘手。NFRC 通常与视图层绑定来处理表视图数据委托请求:NFRC 通知插入、删除、移动、更新更改,委托会适当处理它。然而,在 VIP 架构中,这种情况不会发生,因为 NFRC 无法附加到视图 - 它位于模型层并需要留在那里。
我在 Store 实例中实例化了它,并使 Store 实例成为 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)
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,我初始化一个空数组(开始更新),将所有通知作为事件对象 (PONSOS) 整理到该数组 (I、D、M、U) 中,然后在完成时运行完成处理程序(结束更新)。完成处理程序作为 fetch() 操作的一部分传入并存储以供将来使用 - 即当需要通知 MO 更改时。完成处理程序从交互器传递过来,如下所示:
func processFetchResults(itemChangeEvents: [ItemChangeEvent]) {
let response = ListItems.FetchItems.Response(itemEvents: itemChangeEvents)
presenter?.presentFetchedItems(response: response)
}
Run Code Online (Sandbox Code Playgroud)
因此,它将所有事件传递给演示者,演示者再传递给可以处理这些事件的数据源委托。
但这还不够。为了提高效率,数据源委托确实需要与 NSFRC 交互,以将表视图行映射到正确索引路径处的数据行,处理部分信息等。因此,我所做的是创建一个名为 DynamicDataSource 的协议和一个实现由 Interactor 初始化以“包装”NSFRC 并代理其方法。虽然模型在技术上交给了视图层,但它实际上包装在协议后面,并且实现将 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
}
Run Code Online (Sandbox Code Playgroud)
如果持久性存储更改为内存存储或 JSON 层,则动态数据源实现可以适当处理该问题,而不会影响视图。显然,这是使用 NFRC 的一种复杂方式,但我认为它是一个有用的类。对于一个简单的应用程序来说,这可能有点过分了。然而,它确实有效,而且我认为这是一个很好的、一致的妥协。
值得补充的是,我对 Swift 和 IOS 开发还很陌生,所以这可能不是世界上最好的代码,可能有更好的方法来做到这一点!我始终乐于接受反馈和改进建议。
| 归档时间: |
|
| 查看次数: |
1034 次 |
| 最近记录: |