【问题标题】:Crashing with "failed to scene-update in time" message while calling Core Data Operation调用核心数据操作时出现“未能及时更新场景”消息崩溃
【发布时间】:2015-07-16 11:22:36
【问题描述】:

我面临一个奇怪的问题“未能及时更新场景”。下载数据后,我将其存储到核心数据中。如果应用程序在前台,一切都会正常工作。仅当我在将数据存储到 Core Data 的过程中连续在状态、后台和前台之间切换应用程序时,我才会遇到此崩溃。在调试模式下不会发生这种崩溃。

我尝试将日志放在Core Data操作方法的不同阶段,我发现了应用程序实际崩溃的点。在 UI 中,我使用以下代码

DatabaseManagerClass *database = [[DatabaseManagerClass alloc]init];
[database deleteDataFromFormTable:nil];

[database insertDataInChecklistTable:[self.responseDictionary valueForKey:@"checklists"]];

[self performSelectorOnMainThread:@selector(mainThreadTask) withObject:nil waitUntilDone:YES];`

崩溃发生在方法“insertDataInChecklistTable”中。我检查了 insertDataInChecklistTable 工作的线程。它仅在主线程中。任何人都可以提出一些建议来解决这个问题。

提前致谢, 斯里。

带有执行块的更新代码

-(void)insertDataInFormColumnsTable:(NSMutableArray*)responseArray withForm:(Form*)form

{ AppDelegate objAppDelegate = (AppDelegate)[[UIApplication sharedApplication] delegate];

NSManagedObjectContext *moc   = [objAppDelegate managedObjectContext];
NSManagedObjectContext *bgMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

[bgMOC performBlock:^{
    for (int count=0; count<[responseArray count]; count++)
    {
        NSDictionary *columnDict = [responseArray objectAtIndex:count];

        Form_Column *formColumn = [NSEntityDescription insertNewObjectForEntityForName:@"Form_Column" inManagedObjectContext:moc];


        if ([columnDict valueForKey:FORMULA]!=[NSNull null])        //Added by mritunjay
            formColumn.formula = [columnDict valueForKey:FORMULA];
        else
            formColumn.formula=nil;

        if ([columnDict valueForKey:ASP_EDITABLE]!=[NSNull null])
            formColumn.asp_editable = [columnDict valueForKey:ASP_EDITABLE];
        else
            formColumn.asp_editable=nil;


        if ([columnDict valueForKey:CM_EDITABLE]!=[NSNull null])
            formColumn.cm_editable = [columnDict valueForKey:CM_EDITABLE];
        else
            formColumn.cm_editable=nil;

        if ([columnDict valueForKey:IM_EDITABLE]!=[NSNull null])
            formColumn.im_editable = [columnDict valueForKey:IM_EDITABLE];
        else
            formColumn.im_editable=nil;


        if ([columnDict valueForKey:SP_EDITABLE]!=[NSNull null])
            formColumn.sp_editable = [columnDict valueForKey:SP_EDITABLE];
        else
            formColumn.sp_editable=nil;

        if ([columnDict valueForKey:ASP_EDITABLE]!=[NSNull null])
            formColumn.dialog_row = [columnDict valueForKey:ASP_EDITABLE];
        else
            formColumn.dialog_row=nil;

        if ([columnDict valueForKey:INDEX]!=[NSNull null])
            formColumn.index = [columnDict valueForKey:INDEX];
        else
            formColumn.index=nil;

        if ([columnDict valueForKey:WEB_ONLY]!=[NSNull null])
            formColumn.web_only = [columnDict valueForKey:WEB_ONLY];
        else
            formColumn.web_only=nil;

        if ([columnDict valueForKey:LABEL]!=[NSNull null])
            formColumn.label = [columnDict valueForKey:LABEL];
        else
            formColumn.label=nil;

        formColumn.form_id = form.form_id;

        if ([columnDict valueForKey:ID]!=[NSNull null])
            formColumn.column_id=[columnDict valueForKey:ID];
        else
            formColumn.column_id=nil;

        if ([columnDict valueForKey:TYPE]!=[NSNull null])
            formColumn.type=[columnDict valueForKey:TYPE];
        else
            formColumn.type=nil;

        NSArray *selectionArray = [columnDict valueForKey:SELECTIONS];

        if ([selectionArray count]) {


            for (int count = 0; count < [selectionArray count]; count++)
            {
                Form_Sub_Columns *formSubColumns = [NSEntityDescription insertNewObjectForEntityForName:@"Form_Sub_Columns" inManagedObjectContext:moc];

                NSDictionary *subColumnDict = [selectionArray objectAtIndex:count];

                if ([subColumnDict valueForKey:ID]!=[NSNull null])
                    formSubColumns.column_id=[subColumnDict valueForKey:ID];
                else
                    formSubColumns.column_id=nil;

                if ([subColumnDict valueForKey:LABEL]!=[NSNull null])
                    formSubColumns.label=[subColumnDict valueForKey:LABEL];
                else
                    formSubColumns.label=nil;

                if ([subColumnDict valueForKey:REQUIRES_REMARKS]!=[NSNull null])
                    formSubColumns.requires_remarks=[subColumnDict valueForKey:REQUIRES_REMARKS];
                else
                    formSubColumns.requires_remarks=nil;


                if ([subColumnDict valueForKey:VALUE]!=[NSNull null])
                    formSubColumns.value=[subColumnDict valueForKey:VALUE];
                else
                    formSubColumns.value=nil;


                if ([subColumnDict valueForKey:DESCRIPTION]!=[NSNull null])
                    formSubColumns.description_name=[subColumnDict valueForKey:DESCRIPTION];
                else
                    formSubColumns.description_name=nil;



                if ([subColumnDict valueForKey:SELECTION_TYPE_ID]!=[NSNull null])
                    formSubColumns.selection_type_id=[subColumnDict valueForKey:SELECTION_TYPE_ID];
                else
                    formSubColumns.value=nil;

                [formColumn addSun_columnsObject:formSubColumns];
            }
        }
        [formColumn addFormObject:form];

        [form addColumnsObject:formColumn];

    }

    if([form.enable_attachment boolValue])
    {
        Form_Column *formColumn = [NSEntityDescription insertNewObjectForEntityForName:@"Form_Column" inManagedObjectContext:moc];

        formColumn.label = @"Add Attachments";

        formColumn.form_id = form.form_id;
        formColumn.index = [NSNumber numberWithInt:998];
        formColumn.column_id=[NSNumber numberWithInt:998];    // hardcoded if Attachment is Enabled.
        formColumn.web_only = [NSNumber numberWithInt:0];
        formColumn.type=[NSNumber numberWithInt:-1];

        [form addColumnsObject:formColumn];

    }

    if ([[NSThread currentThread] isMainThread]) {
        NSLog(@"Main Thread inside block");
    }
    else {
        NSLog(@"Not main thread inside block");
    }

    NSError *error;

    if(![bgMOC save:&error]){
        NSLog(@"Error %@", [error localizedDescription]);
    }
}];

}

【问题讨论】:

  • 如果你把实际的堆栈跟踪放在你的问题中会很有帮助,这样我们就可以看到什么时候被调用了。我还建议 NOT 使用-performSelectorOnMainThread:,因为它隐藏了它之前的堆栈跟踪(它基本上被包裹在一个 try/catch 中)。 dispatch_async 是将某些东西放到主线程上的更好解决方案。但总的来说,如果您将数据写入 Core Data 它不应该在主线程上。您阻塞主线程很可能导致此崩溃。
  • 马库斯,感谢您回复我。我理解您所说的 performSelectorOnMainThread:调用选择器方法时不会发生实际崩溃。选择器方法调用前的行,执行数据库操作的方法。崩溃是在这种方法中发生的。所以我不应该在主线程中调用数据库操作。最后,我将日志放入 db 操作方法中,发现实际崩溃发生在 Coredata 的 addObject 方法中。真的很难找到解决方案。
  • 您的崩溃正在发生,因为您阻塞主线程的时间过长并且操作系统正在杀死您的应用程序。在-insertDataInChecklistTable 上放一个断点,看看你在哪个线程上。你在主线吗?如果没有,请发布该方法的代码。
  • Marcus,InsertDataInChecklistTable 方法正在 MainThread 中调用。

标签: ios objective-c multithreading core-data


【解决方案1】:

在主线程/UI 线程上处理数据总是是个坏主意,会导致这样的问题。

您的-insertDataIntoChecklistTable 需要在后台队列中运行,这意味着您应该:

  1. 创建第二个NSManagedObjectContext,即NSPrivateQueueConcurrencyType
  2. 将其与您的主要上下文相关联
  3. 使用-performBlock: 处理针对NSManagedObjectContext 的数据
  4. 处理完成后保存

这将使您的数据处理脱离主队列。永远不要在主队列上处理数据。

【讨论】:

  • 亲爱的马库斯,这是有道理的,我希望这些提示能解决我的问题。我会尝试并让你知道。现在,在 AppDelegate 中初始化的 NSManagedObjectContext 到处都在使用 coredata 操作。那么我应该为每个 coredata 操作创建新的 NSManagedObjectContext 实例吗?非常感谢您的建议。
  • Marcus,我已经通过添加带有执行块的更新代码来编辑我的帖子。我尝试了不同的方式 performBlock 以及 PerformBlockAndWait。 performBlockAndWait 以正常方式工作,但在进入前台和后台时的崩溃仍在发生。这意味着 performBlockAndWait 正在阻塞主线程。在 performBlock 的情况下,我收到一个异常“*** Terminating app due to unaught exception 'NSGenericException', reason: '*** Collection <__nscfset:> was mutated while being enumerated.'”。但我确保该块在不同的线程中运行。
  • -performBlockAndWait: 确实会阻止。这就是AndWait 部分的含义:) 得到“枚举时发生突变”的错误不是核心数据错误,这是一个正常的编程问题,因为您正在枚举一个集合并且您正在改变您正在枚举的集合。这总是很糟糕,并且与这篇 SO 帖子是一个单独的问题。
猜你喜欢
  • 2014-12-07
  • 1970-01-01
  • 1970-01-01
  • 2014-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-24
  • 1970-01-01
相关资源
最近更新 更多