0

我正在尝试确定一个使我的应用程序崩溃多年的错误。然而,我花了很长时间来缩小原因,我想我(几乎)有它。如果应用程序进入后台,它会运行一个后台任务来清理数据库,并在两个月后删除文章订单。

如果碰巧有符合条件的文章,并且 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
4

1 回答 1

1

您正在从异步 GCD 块调用 doMaintainance,并且您正在访问托管对象上下文。

托管对象上下文不是线程安全的

于 2014-01-27T17:41:51.750 回答