Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/103.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 多线程核心数据iOS崩溃_Objective C_Ios_Core Data_Nsmanagedobjectcontext_Nsoperation - Fatal编程技术网

Objective c 多线程核心数据iOS崩溃

Objective c 多线程核心数据iOS崩溃,objective-c,ios,core-data,nsmanagedobjectcontext,nsoperation,Objective C,Ios,Core Data,Nsmanagedobjectcontext,Nsoperation,我正在开发一个iOS应用程序,它使用SQLLite核心数据数据库。该应用程序在后台线程中运行同步循环,从web服务获取数据并将其写入数据库。发生这种情况时,前台(UI)线程继续运行,允许用户对db运行搜索 我正在对应用程序进行压力测试,它正在崩溃。当后台同步任务运行时,我正在前台对数据库进行搜索。数据库中大约有10000条记录,所以不是很大 后台线程是使用NSOperation创建的,它在NSOperation的主方法中创建NSManagedObjectContext 前台线程使用在appDel

我正在开发一个iOS应用程序,它使用SQLLite核心数据数据库。该应用程序在后台线程中运行同步循环,从web服务获取数据并将其写入数据库。发生这种情况时,前台(UI)线程继续运行,允许用户对db运行搜索

我正在对应用程序进行压力测试,它正在崩溃。当后台同步任务运行时,我正在前台对数据库进行搜索。数据库中大约有10000条记录,所以不是很大

后台线程是使用NSOperation创建的,它在NSOperation的主方法中创建NSManagedObjectContext

前台线程使用在appDelegate中初始化(并由appDelegate提供)的不同NSManagedObjectContext对象

后台同步线程一次向数据库写入1000条记录,然后其managedobjectcontext执行保存

NSOperation main方法如下所示:

-(void) main {

    NSDictionary* dictionary = [ HPSJSON getDictionaryFromData:_data ];

    // NEED to create the MOC here and pass to the methods.
    NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] init];
    [moc setUndoManager:nil];
    //[moc setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
    //[moc setMergePolicy:NSOverwriteMergePolicy];
    [moc setPersistentStoreCoordinator:getApp().persistentStoreCoordinator];

    if (dictionary==nil){

        [ getApp().operationManager performSelectorOnMainThread: [ self getFailedFunction ] withObject:nil waitUntilDone:NO ];    
        return;
    }

    NSString* rc = [self processData: dictionary andMOC:moc ]; // Writes lots of records to the db and saves the moc

    // performSelectorOnMainThread invokes a method of the receiver on the main thread using the default mode.
    // i.e. call the method within HPSOperationManager as specified by the getSuccessFunction of the specialised sub-class
    [ getApp().operationManager performSelectorOnMainThread: [ self getSuccessFunction ] withObject:rc waitUntilDone:NO ];        

}
processData方法(由main调用)包含大量代码,但下面是执行保存操作的代码段:

@try {
            NSLog(@"HPSDbOperation%@ about to save Indexes moc",objectName);

            if (rcHappy==YES)
            {
                // register for the moc save notification - this is so that other MOCs can be told to merge the changes
                [[NSNotificationCenter defaultCenter] 
                 addObserver:getApp() 
                 selector:@selector(handleDidSaveNotification:)
                 name:NSManagedObjectContextDidSaveNotification 
                 object:moc];

                NSError* error = nil;
                if ([moc save:&error] == YES)
                {
                    NSLog(@"HPSDbOperation%@ Indexes SAVED",objectName);

                }else {
                    NSLog(@"HPSDbOperation%@ Indexes NOT saved ",objectName);
                }

                // unregister from notification
                [[NSNotificationCenter defaultCenter] 
                 removeObserver:getApp() 
                 name:NSManagedObjectContextDidSaveNotification 
                 object:moc];

            }



        }
        @catch (NSException * e) {
            NSLog(@"HPSDbOperationBase save Indexes Exception: %@", e);
            rcHappy=NO;
        }
appDelegate包含以下处理ManagedObjectContext合并的方法:

- (void)handleDidSaveNotification:(NSNotification*) note 
{

    @try {

        NSLog(@"appDelegate handleDidSaveNotification about to run");
        [__managedObjectContext mergeChangesFromContextDidSaveNotification:note];
        NSLog(@"appDelegate handleDidSaveNotification did run");

    }
    @catch (NSException * e) {
        NSLog(@"appDelegate handleDidSaveNotification Exception: %@", e);
    }

}
我让同步运行,然后通过运行连续搜索来强调前台UI线程。经过一两分钟的同步和搜索,应用程序崩溃了。它似乎没有被我的任何try-catch构造所捕获。Xcode中的崩溃日志显示以下内容:

libobjc.A.dylib`objc_msgSend:
0x34d92f68:  teq.w  r0, #0
0x34d92f6c:  beq    0x34d92faa               ; objc_msgSend + 66
0x34d92f6e:  push.w {r3, r4}
0x34d92f72:  ldr    r4, [r0]  <-- exception here Thread1 EXC_BAD_ACCESS (Code=1)
0x34d92f74:  lsr.w  r9, r1, #2
0x34d92f78:  ldr    r3, [r4, #8]
0x34d92f7a:  add.w  r3, r3, #8
0x34d92f7e:  ldr    r12, [r3, #-8]
0x34d92f82:  and.w  r9, r9, r12
0x34d92f86:  ldr.w  r4, [r3, r9, lsl #2]
0x34d92f8a:  teq.w  r4, #0
0x34d92f8e:  add.w  r9, r9, #1
0x34d92f92:  beq    0x34d92fa6               ; objc_msgSend + 62
0x34d92f94:  ldr.w  r12, [r4]
0x34d92f98:  teq.w  r1, r12
0x34d92f9c:  bne    0x34d9317e               ; objc_msgSendSuper_stret + 34
0x34d92f9e:  ldr.w  r12, [r4, #8]
0x34d92fa2:  pop    {r3, r4}
0x34d92fa4:  bx     r12
0x34d92fa6:  pop    {r3, r4}
0x34d92fa8:  b      0x34d92fb0               ; objc_msgSend_uncached
0x34d92faa:  mov.w  r1, #0
0x34d92fae:  bx     lr
libobjc.A.dylib`objc\u msgSend:
0x34d92f68:teq.w r0,#0
0x34d92f6c:beq 0x34d92faa;objc_msgSend+66
0x34d92f6e:push.w{r3,r4}

0x34d92f72:ldr r4,[r0]多线程核心数据使用的主要规则是托管对象上下文和持久存储的“线程限制”。这意味着,使用线程本地托管对象上下文是安全的,但不能将它们从一个线程传递到另一个线程。如果这样做,您必须自行处理锁定和同步

似乎您在次线程中创建了一个托管对象上下文,然后将其传递给主线程。我理解正确吗?如果是这样,这可以解释你撞车的原因

我想到的一种可能性是:

  • 后台线程保存;发送通知

  • 主线程开始合并

  • 合并正在进行时,后台线程执行另一个保存

  • 不是在第3点“保存”,而是在
    processData
    方法中执行的使moc处于不同状态的任何操作


    在我看来,您应该能够通过已有的日志跟踪轻松验证此事件是否是崩溃的原因。

    您没有创建具有并发类型的上下文,也没有通过父子上下文关系合并更改,因此您可能的问题是线程问题。上下文不是线程安全的,必须在创建上下文的同一个线程上访问或修改上下文

    这在我看来更像是一个与内存相关的问题,你能用zombie profiler在Instruments中运行测试并检查它是否找到了什么吗?如果我自己运行搜索测试就可以了。如果我自己运行同步,就可以了。当我把它们放在一起运行时,它崩溃了。我想这不排除内存问题吧?我会按照你的建议尝试在仪器中运行它-谢谢。好吧,你的崩溃发生在obj_msgSend中,它是一种向对象发送消息的方法(即调用对象上的方法),它会与EXC_BAD_访问崩溃,这表明内存访问错误,所以我不排除内存相关的问题,但它当然也可能与多线程相关。这可能不会有帮助,但有可能……尝试使用Xcode断点导航器底部的“+”符号在Objective-C异常上设置断点。它有时会导致调试器提供更多有用的信息。是的,这正是我正在做的。但是我需要UI线程“查看”后台线程添加的新记录,那么如何将后台更改合并到前台上下文中呢?谢谢。不过,我认为合并上下文正是NSManagedObjectContextDidSaveNotification的核心所在?事实上,你是对的。。。您可以在调用
    mergeChanges…
    unlock
    之前尝试将
    -[NSManagedObjectContext lock]
    放入。我尝试将我的mergeChangesFromContextDidSaveNotification包装在try lock/unlock中,但在一两分钟的测试后(测试期间一切正常),应用程序仍然崩溃。