简体   繁体   English

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

[英]Core Data crashing when doing count request using performBlock

My iOS app is crashing when doing two calls to countForFetchRequest at the same time on the same private queue NSManagedObjectContext using performBlock. 使用performBlock在同一私有队列NSManagedObjectContext上同时对countForFetchRequest进行两次调用时,我的iOS应用程序崩溃。

I setup my childContext like this 我这样设置了我的childContext

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

And this is my performBlock that calls countForFetchRequest 这是我的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);
    }
}];

And here is the crash log: 这是崩溃日志:

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

Am I using the performBlock correctly? 我是否正确使用performBlock?

Edit: More details 编辑:更多详细信息

The performBlock is being called in a webViewDidFinishLoad:webView delegate method. 在webViewDidFinishLoad:webView委托方法中调用performBlock。 I have multiple UIWebViews and when they finish loading they are calling the delegate method which is in turn calling the performBlock to see if it needs to add the url to the core data database. 我有多个UIWebViews,当它们完成加载时,它们正在调用委托方法,该方法又依次调用performBlock以查看是否需要将url添加到核心数据数据库中。

You can encapsulate the method causing the crash in: 您可以将导致崩溃的方法封装在:

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

This will make sure that even while multithreading, the piece of code inside will be running just once at a time ... other threads will just have to wait. 这样可以确保即使在多线程处理中,其中的代码一次也只能运行一次……其他线程将只需要等待。 Frankly, this will work only if the cause of the crash is the concurrency. 坦白说,只有当崩溃的原因是并发时,这才起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM