これは私が最後にしたものです。 NSFetchedResultsController(NFRC)には、データを取得すること、つまりクエリを実行すること、および代理コールを介してManagedObject(MO)に変更を通知することの2つの方法でアプローチする必要があります。
データを取得しても、代理コールが発生しません。そのため、通常はフェッチを実行した結果、つまりNFRC.fetchedObjects()、PONSOSを作業者またはインタラクタに再パッケージし、これらをPresenterに渡してViewControllerに渡します。
DataSource DelegateをViewController(テーブルビューが実装の一部である場合)として使用するのがより簡単で、それと同様に、ViewControllerの別のクラスとして実装しました。
このアプローチでは、標準VIPサイクルが維持され、ビューレイヤにモデルに関する知識は必要ありません。
デリゲートコールの処理はやや難解です。 NFRCは、挿入、削除、移動、更新の変更を通知し、デリゲートがそれを適切に処理することをNFRCが通知するため、通常、Viewレイヤに関連付けられています。しかし、NFRCをViewにアタッチすることができないVIPアーキテクチャでは、Modelレイヤーに存在し、そこにとどまる必要があります。
私は、ストアインスタンスでこれをインスタンス化などの店舗インスタンスに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)
}
だから、それらを処理することができ、データソースデリゲートに渡すプレゼンターにすべてのイベントを渡します。
しかし、これでは不十分です。効率を上げるために、データソースデリゲートは実際にNSFRCと対話して、テーブルビュー行を正しいインデックスパスのデータ行にマッピングし、セクション情報などを処理する必要があります。したがって、私はDynamicDataSourceと呼ばれるプロトコルを作成しました。インタラクタがNSFRCを「ラップ」し、そのメソッドをプロキシするために初期化されたものの実装。モデルは技術的にViewレイヤーに渡されますが、実際にはプロトコルの後ろにラップされ、実装はMOをPONSOSに変換します。プレゼンターレイヤーの拡張子(スウィフト拡張子ではありません)を参照してください。永続ストアに変更された場合は
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の開発にかなり新しいので、これは世界でも最高のコードではないかもしれないし、それを行う良い方法があるかもしれません。私は常に改善のためのフィードバックや提案をしています。