這就是我最後做的。需要通過兩種方式處理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開發非常陌生,所以這可能不是世界上最好的代碼,並且可能有更好的方法來實現它!我始終樂於接受反饋和改進建議。