使用performBlock进行计数请求时核心数据崩溃

问题描述:

当使用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

可以封装方法导致崩溃:

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

这将确保即使在多线程的代码段内将在同一时间只有一次运行...其他线程将只必须等待。坦率地说,只有当崩溃的原因是并发时,这才会起作用。

+4

'performBlock:'的要点是处理并发性,确保一次只有一个线程调用块代码。 – 2013-02-13 17:18:02

+0

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