奇妙な動作を示す Core Data バックエンドがあります。(シミュレーターで) アプリを初めて実行するとき、NSFetchRequest は、同一のアイテムが連続して複数回与えられた場合でも、一致するものを見つけることはありません (各リクエストで「結果なし」が返され、重複した情報がデータベースに挿入されます。データベースに関連付けられたテーブルビューがあるため、発生する可能性があります)。
ホームボタンを押してアプリを「終了」した場合は、アプリを再度開きます。期待どおりに動作し始めます (必要に応じて結果を返します)。アプリを削除して Xcode から再度実行し、このプロセスを最初にリセットすることもできます。NSManagedObjectContext (true を返す) で save を呼び出しているにもかかわらず、アプリが閉じるまでデータベースを保存しないようです。
何が起きてる?これを期待どおりに機能させるにはどうすればよいですか? NSManagedObjectContext の変更を保存していないだけだと思っていますが、どうすればよいですか?
NSManagedObjectContext からオブジェクトを取得/返す関数は次のとおりです。
+ (Mark *)markWithTWLInfo:(NSDictionary *)markDictionary
inManagedObjectContext:(NSManagedObjectContext *)context
{
Mark *mark = nil;
NSLog(@"Starting Operation for Key: %@", [markDictionary[JS_MARK_ID] description]);
// Build a fetch request to see if we can find this Mark in the database.
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Mark"];
request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES]];
request.predicate = [NSPredicate predicateWithFormat:@"idUnique = %@", [markDictionary[JS_MARK_ID] description]];
// Execute the fetch
NSError *error = nil;
NSArray *matches = [context executeFetchRequest:request error:&error];
// Check what happened in the fetch
if (!matches || ([matches count] > 1) || error ) { // nil means fetch failed; more than one impossible (unique!)
// handle error
if (error) {
NSLog(@"Fetch error: %@", [error description]);
} else {
NSLog(@"Found No/Multiple matches for key: %@", [markDictionary[JS_MARK_ID] description]);
}
} else if (![matches count]) { // none found, so let's create a mark
NSLog(@"Inserting: %@", [markDictionary[JS_MARK_ID] description]);
mark = [NSEntityDescription insertNewObjectForEntityForName:@"Mark" inManagedObjectContext:context];
mark.idUnique = [NSNumber numberWithInt:[markDictionary[JS_MARK_ID] intValue]];
//Save the changes; this returns True
if ([context save:&error]) {
NSLog(@"Saved is true");
} else {
NSLog(@"Saved is false");
}
if (error) {
NSLog(@"Save error: %@", [error description]);
}
} else { // found the mark, just return it from the list of matches (which there will only be one of)
NSLog(@"Found existing object for key: %@", [markDictionary[JS_MARK_ID] description]);
mark = [matches lastObject];
}
return mark;
}
挿入するすべてのマークに対して、この関数を次のように呼び出します。
for (NSDictionary *mark in results) {
if (DEMO_LOGGING) NSLog(@"Inserting: %@",[mark objectForKey:@"Mark"]);
[self.managedObjectContext performBlock:^{
[Mark markWithTWLInfo:[mark objectForKey:@"Mark"] inManagedObjectContext:self.managedObjectContext];
}];
}
この問題が発生したときにログに表示される内容は次のとおりです。
-新しいデータベースでアプリを起動します:
2013-05-05 16:45:08.105 ToWatchList[10155:c07] Starting Operation for Key: 731
2013-05-05 16:45:08.106 ToWatchList[10155:c07] Inserting: 731
2013-05-05 16:45:08.111 ToWatchList[10155:c07] Saved is true
2013-05-05 16:45:10.651 ToWatchList[10155:c07] Starting Operation for Key: 731
2013-05-05 16:45:10.652 ToWatchList[10155:c07] Inserting: 731
2013-05-05 16:45:10.654 ToWatchList[10155:c07] Saved is true
-ここでプログラムを終了して再起動します
2013-05-05 16:45:29.816 ToWatchList[10155:c07] Starting Operation for Key: 731
2013-05-05 16:45:29.817 ToWatchList[10155:c07] Found No/Multiple matches for key: 731
- NSFetchRequest は期待どおりに前の 2 つのエントリを返すようになりましたが、2 番目のエントリを挿入しようとしたときに最初のエントリが表示されるはずでした。