2013-02-13 107 views
1

當使用performBlock在同一個專用隊列NSManagedObjectContext上同時對countForFetchRequest執行兩個調用時,我的iOS應用程序崩潰。使用performBlock進行計數請求時核心數據崩潰

設置我childContext這樣

_childContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
[_childContext setParentContext:self.managedObjectContext]; 

這是我performBlock調用countForFetchRequest

[self.childContext performBlock:^{ 
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"History"]; 

    fetchRequest.predicate = [NSPredicate predicateWithFormat:@"url == %@", url]; 

    NSError *error = nil; 

    NSUInteger num = [self.childContext countForFetchRequest:fetchRequest error:&error]; 

    if(error != nil){ 
     NSLog(@"Error getting count for history url %@ %@", url, error); 
     return; 
    } 

    if(num > 0){ // Already have this in the history, don't re-add it 
     return; 
    } 

    History *history = (History *)[NSEntityDescription insertNewObjectForEntityForName:@"History" inManagedObjectContext:self.childContext]; 

    history.url = url; 
    history.title = title; 

    if(![self.childContext save:&error]){ 
     NSLog(@"Error occurred saving history item %@ %@ %@", title, url, error); 
    } 
}]; 

這裏是崩潰日誌:

Thread 0 name: Dispatch queue: com.apple.main-thread 
Thread 0 Crashed: 
0 libsystem_kernel.dylib   0x3a427350 __pthread_kill + 8 
1 libsystem_c.dylib    0x3a39e11e pthread_kill + 54 
2 libsystem_c.dylib    0x3a3da96e abort + 90 
3 libc++abi.dylib     0x39978d4a abort_message + 70 
4 libc++abi.dylib     0x39975ff4 default_terminate() + 20 
5 libobjc.A.dylib     0x39f29a74 _objc_terminate() + 144 
6 libc++abi.dylib     0x39976078 safe_handler_caller(void (*)()) + 76 
7 libc++abi.dylib     0x39976110 std::terminate() + 16 
8 libc++abi.dylib     0x39977594 __cxa_rethrow + 84 
9 libobjc.A.dylib     0x39f299cc objc_exception_rethrow + 8 
10 CoreData      0x31e868e0 -[NSManagedObjectContext(_NSInternalAdditions) _countWithNoChangesForRequest:error:] + 764 
11 CoreData      0x31e833fe -[NSManagedObjectContext countForFetchRequest:error:] + 1062 
12 CoreData      0x31e92470 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0 + 460 
13 libdispatch.dylib    0x3a345d26 _dispatch_barrier_sync_f_slow_invoke + 82 
14 libdispatch.dylib    0x3a3404b4 _dispatch_client_callout + 20 
15 libdispatch.dylib    0x3a3451b8 _dispatch_main_queue_callback_4CF$VARIANT$mp + 220 
16 CoreFoundation     0x3205cf36 __CFRunLoopRun + 1286 
17 CoreFoundation     0x31fcfeb8 CFRunLoopRunSpecific + 352 
18 CoreFoundation     0x31fcfd44 CFRunLoopRunInMode + 100 
19 GraphicsServices    0x35b992e6 GSEventRunModal + 70 
20 UIKit       0x33ee52fc UIApplicationMain + 1116 
21 Accountable2You Mobile   0x000e5d28 0xe4000 + 7464 
22 Accountable2You Mobile   0x000e5cc4 0xe4000 + 7364 

Thread 1 name: Dispatch queue: NSManagedObjectContext Queue 
Thread 1: 
0 libsystem_kernel.dylib   0x3a416f04 semaphore_wait_trap + 8 
1 libdispatch.dylib    0x3a3462fc _dispatch_thread_semaphore_wait$VARIANT$mp + 8 
2 libdispatch.dylib    0x3a34487c _dispatch_barrier_sync_f_slow + 96 
3 CoreData      0x31e82df2 _perform + 166 
4 CoreData      0x31e921c6 -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] + 238 
5 CoreData      0x31e86770 -[NSManagedObjectContext(_NSInternalAdditions) _countWithNoChangesForRequest:error:] + 396 
6 CoreData      0x31e833fe -[NSManagedObjectContext countForFetchRequest:error:] + 1062 
7 Accountable2You Mobile   0x000ee7be 0xe4000 + 42942 
8 CoreData      0x31e86072 developerSubmittedBlockToNSManagedObjectContextPerform_privateasync + 66 
9 libdispatch.dylib    0x3a344eca _dispatch_queue_drain$VARIANT$mp + 138 
10 libdispatch.dylib    0x3a344dbc _dispatch_queue_invoke$VARIANT$mp + 36 
11 libdispatch.dylib    0x3a34591a _dispatch_root_queue_drain + 182 
12 libdispatch.dylib    0x3a345abc _dispatch_worker_thread2 + 80 
13 libsystem_c.dylib    0x3a375a0e _pthread_wqthread + 358 
14 libsystem_c.dylib    0x3a3758a0 start_wqthread + 4 

我使用的performBlock正確嗎?

編輯:更多細節

的performBlock被稱爲在webViewDidFinishLoad:web視圖委託方法。我有多個UIWebViews,當他們完成加載時,他們調用委託方法,該方法又調用performBlock來查看是​​否需要將url添加到核心數據數據庫。

+0

聽起來像 - 從標題 - 的崩潰行countForFetchRequest?你可以嘗試沒有線程(主要)排除查詢中的其他問題? – danh 2013-02-13 15:46:21

+0

顯示如何在同一個線程上調用兩次。 – Mundi 2013-02-13 16:31:12

+0

@Mundi我編輯了這個問題,包含一些關於它如何被調用的附加信息。 – Austin 2013-02-13 16:47:43

回答

0

可以封裝方法導致崩潰:

@synchronized(self) { 
    [object yourMethod]; 
} 

這將確保即使在多線程的代碼段內將在同一時間只有一次運行...其他線程將只必須等待。坦率地說,只有當崩潰的原因是併發時,這纔會起作用。

+4

'performBlock:'的要點是處理併發性,確保一次只有一個線程調用塊代碼。 – 2013-02-13 17:18:02

+0

感謝您的澄清...我想我已經嘟that了一下:) – Ondrej 2013-02-13 17:20:11