我正在開發一個使用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