Автоматический UITableView с использованием NSFetchedResultsController, находясь в фоновом режиме
Я пытаюсь зафиксировать ошибку, которая испортила мое приложение целую вечность. Однако мне потребовалось много времени, чтобы выяснить причину, и я думаю, что у меня (почти) есть это. Если приложение переходит в фоновый режим, оно запускает фоновую задачу для очистки базы данных и удаления порядка статей через два месяца.
Если так получилось, что есть статьи, которые соответствуют требованиям, и открыт UITableView, который показывает этот конкретный список, то приложение вылетает, как запрос NSFetchedResultsController
часто приводит к следующей ошибке:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'no section at index 26'
или иногда:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
при вызове: (_objects является NSFetchedResultsController)
[_objects objectAtIndexPath:[NSIndexPath indexPathForRow:currentRow inSection:indexPath.section]]
вызваны
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
Так что мне было интересно, если это потому, что NSFetchedResultsController
(в главном потоке) недоступен (должным образом) для фоновой задачи / потока, когда приложение прекратило работу. Это объяснение? И если так, как я могу предотвратить это правильно?
Я могу предотвратить ManagedObjectContect
чтобы объединить изменения, но как мне убедиться, что они обновлены, и изменения отражены в UITableView
когда приложение вернется на передний план?
Только теория. Я знаю, что сбой происходит в фоновом режиме, но пока не намного. Обновление, удаление, удаление работает нормально, когда приложение активно.
ОБНОВЛЕНО исправлением кода: вызов фонового процесса
- (void)performMaintenance{
UIApplication *application = [UIApplication sharedApplication]; //Get the shared application instance
__block UIBackgroundTaskIdentifier background_task; //Create a task object
background_task = [application beginBackgroundTaskWithExpirationHandler: ^ {
[application endBackgroundTask: background_task]; //Tell the system that we are done with the tasks
background_task = UIBackgroundTaskInvalid; //Set the task to be invalid
//System will be shutting down the app at any point in time now
}];
//Background tasks require you to use asyncrous tasks
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Perform your tasks that your application requires
NSLog(@"\n\nRunning maintenance in the background!\n\n");
// Perform work that should be allowed to continue in background
[self doMaintenance];
[application endBackgroundTask: background_task]; //End the task so the system knows that you are done with what you need to perform
background_task = UIBackgroundTaskInvalid; //Invalidate the background_task
});
}
#pragma mark Actions
- (void)doMaintenance{
DODataManager *data = [[DODataManager alloc] init];
NSDateComponents *components = [[NSDateComponents alloc] init];
components.month = -2;
NSDate *twoMonthsBeforeNow = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:[NSDate date] options:0];
NSFetchedResultsController* controller = [data getArticlesBeforeDate:twoMonthsBeforeNow];
NSLog(@"Cleaning up database, removing %i items", controller.fetchedObjects.count);
for(DOArticle* article in controller.fetchedObjects){
[controller.managedObjectContext deleteObject:article];
}
// Update the unread count and unread count (if dataconenction available)
[data updateBadge];
[data commitChanges];
data=nil;
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObject:@"1.0" forKey:@"progress"];
[[NSNotificationCenter defaultCenter] postNotificationName:kDialogUpdate object:dict];
NSLog(@"Finished maintenace!");
}
Очистка теперь происходит должным образом в отдельном потоке, и уведомления отправляются в основной поток, но проблема остается той же.
2014-01-27 22:16:34.541 iDomsPortalDev[1963:5107] Cleaning up database, removing 2 items
2014-01-27 22:16:36.024 iDomsPortalDev[1963:5107] Start for 3 items on object Setting!
2014-01-27 22:16:36.026 iDomsPortalDev[1963:5107] Removing 0 stat items
2014-01-27 22:16:36.029 iDomsPortalDev[1963:70b] Merging changes!
2014-01-27 22:16:36.030 iDomsPortalDev[1963:70b] Delete
1 ответ
Вы вызываете doMaintainance из асинхронного блока GCD и получаете доступ к контексту управляемого объекта.
Контексты управляемых объектов не являются потокобезопасными