我正在开发一个使用SQLLite核心数据数据库的iOS应用程序。该应用程序在后台线程中运行同步循环,后者从Web服务获取数据并将其写入数据库。前景(UI)线程在这种情况下继续,允许用户针对数据库运行搜索。多线程核心数据iOS崩溃
我压力测试应用程序,它崩溃了。在后台同步任务运行时,我正在前台运行对数据库的搜索。数据库中有大约10,000条记录,所以它不是很大。
后台线程使用NSOperation创建,它在NSOperation的main方法中创建NSManagedObjectContext。
前台线程使用一个不同的NSManagedObjectContext对象,该对象在appDelegate中被初始化(并被提供)。
后台同步线程一次向数据库写入一千条记录,然后其managedobjectcontext执行保存。
的的NSOperation主要方法是这样的:
-(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 ];
}
的过程数据的方法(通过主调用)包含了大量的代码,但这里是片段,它保存:
@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
我对iOS和objective-c以及核心数据都很陌生。我有点卡住如何推进这个问题。我如何知道应用程序出错的位置/原因?任何人都知道为什么它可能会崩溃?我已经对核心数据中的多线程做了一些阅读,我相信通过在NSOperation的主要方法中创建MOC,我遵循指导原则,并且通过使用handleDidSaveNotification,我也正确地合并了我的MOC。
帮助!谢谢。
这看起来更像是一个与内存相关的问题,您可以使用僵尸分析器在仪器中运行测试并检查它是否找到什么? – JustSid 2012-07-26 19:03:13
如果我自己运行搜索测试,那很好。如果我自己运行同步,那很好。当我把它们撞在一起时,它就会崩溃。我认为这并不排除内存问题?我会尝试在乐器中运行它,谢谢。 – whatdoesitallmean 2012-07-26 19:06:34
好吧,你的崩溃发生在obj_msgSend这是发送消息到一个对象的方法(即调用它的方法),它崩溃与一个EXC_BAD_ACCESS这表明存储器访问错误,所以我不会排除一个内存相关的问题,但它当然也可以与多线程相关。 – JustSid 2012-07-26 19:11:02