私は今、厄介なCoreDataの問題で約2週間立ち往生しています。たくさんのブログ投稿、記事、SOの質問/回答を読みましたが、それでも問題を解決できません。
私はたくさんのテストを実行し、大きな問題を小さな問題に減らすことができました。大きな説明になるので、私と一緒にいてください!
問題-データモデル
次のデータモデルを取得する必要があります:
オブジェクトAはオブジェクトBと1対多の関係にあり、オブジェクトBには別の1対多の関係があります。コアデータの推奨事項のため、Bの各インスタンスがその親Aを指し、同じ親Bを指すC。
A <->> B <->> C
問題-MOCの設定
バターのようにスムーズな応答性を維持するために、3レベルのmanagedObjectContext構造を作成しました。
- 親MOC-を使用して独自のプライベートスレッドで実行され
NSPrivateQueueConcurrencyType
、persistentStoreCoordinator
- MainQueue MOC-を使用してmainThreadで実行され、
NSMainQueueConcurrencyType
親MOC1があります - 解析操作ごとに、プライベートキューと親mainQueueMOCを持つ3番目のMOCを作成します。
私のメインデータコントローラーは、MOC 2の通知にオブザーバーとして追加されるNSManagedObjectContextDidSave
ため、MOC 2performBlock:
がMOC1に保存するたびに、保存操作を実行するトリガーがトリガーされます(のために非同期にperformBlock:
)。
問題-構文解析
大きなJSONファイルをコアデータ構造に解析するために、繰り返しパーサーを作成しました。このパーサーは、新しいMOC(3)を作成することから始まります。次に、オブジェクトAのデータを取得し、そのプロパティを解析します。次に、パーサーはBのJSONリレーションを読み取り、データで満たされた対応するオブジェクトを作成します。これらの新しいオブジェクトは、Aを呼び出すことによってAに追加されますaddBObject:
。パーサーは繰り返し発生するため、Bの解析はCの解析を意味し、ここでも新しいオブジェクトが作成されてBにアタッチされます。これはすべてMOC3でperformBlock:
行われます。
- 解析(「A」オブジェクトを作成し、Bの解析を開始します)
- Aの解析(「B」オブジェクトを作成し、それらをAにアタッチして、Cの解析を開始します)
- Bの解析(「C」オブジェクトを作成し、それらをBにアタッチします)
- Cの解析(データをCオブジェクトに格納するだけ)
- Bの解析(「C」オブジェクトを作成し、それらをBにアタッチします)
- Aの解析(「B」オブジェクトを作成し、それらをAにアタッチして、Cの解析を開始します)
各解析操作の後に、MOC 3を保存し、mainThreadにメインMOCの保存操作をディスパッチします(2)。通知のため、NSManagedObjectContextDidSave
MOC1は非同期で自動保存します。
if (parsed){
NSError *error = nil;
if (![managedObjectContext save:&error])
NSLog(@"Error while saving parsed data: %@", error);
}else{
// something went wrong, discard changes
[managedObjectContext reset];
}
dispatch_async(dispatch_get_main_queue(), ^{
// save mainQueueManagedObjectContext
[[HWOverallDataController sharedOverallDataController] saveMainThreadManagedObjectContext];
});
メモリフットプリントを解放するため、そして今のところデータを解析する必要がないため、次のことを実行しています。
[a.managedObjectContext refreshObject:a mergeChanges:NO];
解析されたAIごとに。
約10個のAを解析する必要があるため、すべてが約10個のBを持ち、すべてが約10個のCを持ち、多くのmanagedObjectが生成されます。
問題-楽器
すべてが正常に動作します。唯一のことは、割り当てツールをオンにすると、リリースされていないA、B、およびCが表示されることです。私は彼らのretainCountsなどから有用な情報を取得していません。そして、私の実際の問題はより複雑なdataModelに関するものであるため、生きているオブジェクトは深刻なメモリの問題になります。誰かが私が間違っていることを理解できますか?正しいmanagedObjectを使用して他のmanagedObjectContextsでrefreshObjectsを呼び出すことも機能しません。ハードだけが機能しているreset
ように見えますが、UIで使用される生きているオブジェクトへのポインターを失います。
私が試した他の解決策
双方向の関係ではなく、一方向の関係を作成してみました。これにより、コアデータの不整合や奇妙な動作を引き起こす他の多くの問題が発生します(オブジェクトのぶら下がりやコアデータがnn関係ではなく1-n関係を生成するなど(逆の関係が不明なため)。
NSManagedObjectContextDidSave
オブジェクトの通知を取得するときに、変更または挿入された各オブジェクトを更新してみました
これらの両方の「ソリューション」(ちなみに機能しません)も少しハッキーなようです。これは行く方法ではありません。ただし、メモリフットプリントを増やすことなく、UIをスムーズに保つことで、これを機能させる方法があるはずです。
-CodeDemo
-さらなる調査
mainContext(mainSaveの後)でこれまでに使用されたすべてのオブジェクト(面倒な作業)を更新した後、オブジェクトのサイズは48バイトに縮小されます。これは、オブジェクトにすべて障害が発生しているが、メモリにポインタが残っていることを示しています。すべて障害が発生している約40.000のオブジェクトがある場合でも、メモリには1.920 MBがあり、persistentManagedObjectContextがリセットされるまで解放されません。そして、これは、managedObjectへのすべての参照を失うため、やりたくないことです。