私は、かなり大きなデータオブジェクトグラフを管理するために、コアデータをモジェネレータと組み合わせて使用しています。CoreData + mogenerator - 中間データモデルの `setValue(forKey:)`が最終データモデルのエンティティの '人間'クラスを参照するのを防ぐにはどうすればいいですか?
過去にいくつかの不都合な決定があったため(データをTransformable
というオブジェクトに格納する)、マイグレーションを実行するときにメモリの問題が発生しました。軽量化ではカバーできないほど移行が難しく、カスタム移行ではすべてのものをメモリにロードしようとしていて悲惨に失敗します。
Marcus Zarraの優れたCore Data bookに基づいて、軽量でカスタムの、または独自のマイグレーション戦略を作成して、連続したマイグレーションパスをミックス&マッチさせるためのプログレッシブマイグレーション手法を採用しました。私はこれを使用して私の '大きなデータ'オブジェクトを読み込んでそれをディスク上の外部ファイルに書き出す中間データモデルを作成し、代わりにそのファイルにURLを保存します。
基本的に、これは次のようになります。2つの軽量の移行の間に
v1 ----(lightweight)----------> v1.5 --(lightweight)--> v2
| |
* myData: Transformable | * myData: Transformable? | * myDataUrl: String
| * myDataUrl: String |
、私はfetchLimit
、fetchBatchSize
を使用して変更する必要があるオブジェクトをフェッチ、中間モデルにNSPersistentStoreController
をフックアップ。ディスク上のファイルにデータを書き出し、オブジェクト自体に格納されているデータを無効にします。その間、私は定期的にmocを保存し、処理されたオブジェクトをフォールトします。
これはむしろうまくいくのですが、マイグレーションの別の部分がうまくいかず、関係を削除して、それをmogeneratedファイルの 'Human'クラスの計算されたプロパティに置き換えました。すなわち、同じ原則に沿って
v1 ----(lightweight)----------> v1.5 --(lightweight)--> v2
| |
* myRel ->> [Some object] | * myRel ->> [Some object]? | (nothing stored here)
computed property `myRel` in the `MyEntity` human class
、「V1.5ツーV1.5」で、私は別のレベルにmyRel
に格納されている情報を移動し、nil
に関係を設定しようとしている、合格その後。データ型v2を使用するアプリケーションは、同じインタフェースを使用してmyRel
で参照されているオブジェクトにまだアクセスします。なぜなら、移動したデータを取得する計算されたプロパティとして追加したからです。
public var myRel: [Some object] { return ... }
ここでは、この動きませんコードです:
// Note that since I'm not working on the current data model version in this
// so-called migration pass, I cannot/should not refer to the real `MyEntity` class that
// mogenerator generates for me.
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "MyEntity")
let objects = try? moc.fetch(fetchRequest)
objects.forEach { object in
// Process objects in `myRel` and move them to a different level
let toProcess = ($0.value(forKey: "myRel") as? NSOrderedSet)?.array as? [NSManagedObject]?
// ... process ...
// Now nullify the original relationship
$0.setValue(nil, forKey: "myRel")
}
この最後の行は、最終的なモデルバージョン用に生成された「オブジェクト」ファイルmogeneratorにつながるスタックトレースを示し、実行時のクラッシュの原因ではなく、私が働いている上でのデータモデルは、私の計算されたプロパティで言及したエンティティが含まれていないため、この中間モデル
#0 0x0000000100f6885e in MyEntity.myRel.getter at ...
#1 0x0000000100f68732 in @objc MyEntity.myRel.getter()
#2 0x000000010ebf7db7 in _PF_Handler_Public_GetProperty()
#3 0x000000010124f221 in NSKeyValueWillChangeBySetting()
#4 0x0000000101249798 in NSKeyValueWillChange()
#5 0x000000010121f618 in -[NSObject(NSKeyValueObserverNotification) willChangeValueForKey:]()
#6 0x0000000100f47222 in NSManagedObject.setValue<A where ...> (Any?, for : A) ->() at ...
のために当然のことながら、これはクラッシュ(もののみデータモデルv2の上に存在している)
これは私の驚き、私は特にMyEntity
クラスの基礎となる動的論理「を離れてスライス」したのを期待して<NSManagedObject>
とNSFetchRequest
を構築し、それがコアデータ/スウィフト推論と思われます実行時の型はエンティティ名/記述に基づいています。これを回避する方法はありますか?
私もsetPrimitiveValue
を使ってみましたが、それが私のオブジェクトに加えた変更を見逃してしまいます。
これをすべて書き留めてみると、やや明るく見えました。 中間データモデルのmyRelをmyRelOldに変更し、中間変換でその名前にアクセスすることで、この問題を回避することができました。データモデルv2への移行で関係が削除されるため、これはあまり重要ではありません。 まだ、Core Dataが中間のものの代わりに「現在のデータモデル」エンティティを使用しようとしている理由について、誰かが私にポインタを与えることができれば、最新モデルの私の計算されたプロパティは '@dynamic' /' @ NSManaged'とマークされていないことに注意してください。または私がやっていることに新鮮な光を見せて、いつでも歓迎してください! – Stavr0s