Базовые данные: NSManagedObjectContext не сохранен / запрос выборки не выполняется до тех пор, пока приложение не закроется и не перезапустится
У меня есть Core Data Backend, который демонстрирует странное поведение. Когда я запускаю свое приложение в первый раз (в симуляторе), мой NSFetchRequest никогда не найдет совпадения, даже если ему будут присвоены идентичные элементы несколько раз подряд (он будет возвращать "нет результатов" каждый запрос, затем перейдет к вставке дублированной информации в базу данных, которую я может произойти, потому что у меня есть табличное представление, привязанное к базе данных).
Если я "выйду" из приложения, нажав кнопку "Домой", то снова откройте приложение. Он начинает вести себя как ожидалось (возвращая результаты, где это уместно) Я также могу удалить приложение и затем запустить его снова из XCode, чтобы сбросить этот процесс обратно в начало. Кажется, он не сохраняет базу данных до тех пор, пока приложение не закроется, хотя я вызываю save для NSManagedObjectContext (который возвращает true).
Что тут происходит? Как мне сделать эту работу, как ожидалось? Я думаю, что просто не сохраняю свои изменения для 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
-Now NSFetchRequest возвращает мои 2 предыдущие записи, как и ожидалось, но он должен был увидеть первую, когда он пытался вставить вторую.
1 ответ
Я предполагаю, что у вас есть родительский контекст для вашего self.managedObjectContext
,
В этом случае для обеспечения уникальности свойства вам придется сохранить весь путь до магазина (рекурсивно сохранять до parentContext
существует).
Обратите внимание, что вы должны дождаться завершения сохранения во всех родительских контекстах, прежде чем сможете гарантировать уникальность.
замени свой [context save:&error]
с:
NSManagedObjectContext* c = context;
__block BOOL success = YES;
while (c && success) {
[c performBlockAndWait:^{
success = [c save:&error];
//handle save success/failure
}];
c = c.parentContext;
}