在尝试访问获取对象的属性时,为什么会出现CoreData多线程违规?

时间:2015-08-10 09:34:22

标签: ios objective-c xcode multithreading core-data

以下代码在没有最后一个语句的情况下运行良好。但是,在最后一行,Xcode停止并显示以下消息:

  

CoreData` + [的NSManagedObjectContext   的 Multithreading_Violation_AllThatIsLeftToUsIsHonor ]:

 NSManagedObjectContext *context = GLOBAL_appDelegate.coreDataHelper.contextBackground;
    [context performBlock:^{
         NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
         [fetchRequest setEntity:[NSEntityDescription entityForName:@"CdTag" inManagedObjectContext:context]];
         NSPredicate *predicate = [NSPredicate predicateWithFormat:@"title BEGINSWITH[cd] %@", @"webpages"];
         [fetchRequest setPredicate:predicate];
         NSArray *cdTags = [context executeFetchRequest:fetchRequest error:nil];
         NSLog(@"number of tags: %li", cdTags.count);
         CdTag *cdTag = [cdTags objectAtIndex:0];

         // Accessing a property causes the assertion warning to be shown
         cdTag.title;
    }];

我正在使用Xcode 7 beta 5并启用了多线程断言。

上下文定义如下:

_model = [NSManagedObjectModel mergedModelFromBundles:nil];
_coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_model];
_context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_context setPersistentStoreCoordinator:_coordinator];

_contextBackground = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_contextBackground setParentContext:_context];

这是一个Xcode错误还是我做错了什么?

2 个答案:

答案 0 :(得分:5)

您能否在上下文初始化时添加代码?

您获得的错误与从初始化的线程/队列之外的线程/队列访问托管对象上下文有关。

通常会发生的事情是使用默认/遗留“限制类型”并发类型初始化托管对象上下文

performBlock: 

performBlockAndWait:

方法实际上不会做他们做广告的事情,即确保在初始化时与其关联的队列上访问上下文。

如果我上面提到的是实际发生的事情你可以(假设其他一切都已到位)通过初始化你的上下文来解决这个问题:

_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

以下是并发策略的文档:

  

使用initWithConcurrencyType:创建托管对象上下文时,您的线程(队列)关联有三个选项

     

限制(NSConfinementConcurrencyType)

     

为了向后兼容,这是默认设置。您保证除了您创建它之外的任何线程都不会使用上下文。通常,为了使行为明确,我们鼓励您使用其他类型之一。

     

如果托管对象上下文的父存储是持久性存储协调器,则只能使用此并发类型。

     

专用队列(NSPrivateQueueConcurrencyType)

     

上下文创建并管理专用队列。

     

主队列(NSMainQueueConcurrencyType)

     

上下文与主队列相关联,因此与应用程序的事件循环相关联,但它在其他方面类似于基于私有队列的上下文。您可以将此队列类型用于链接到控制器和UI对象的上下文,这些对象只需要在主线程上使用。

     

如果您使用限制模式使用上下文,则直接发送上下文消息;由您来确保从正确的队列发送消息。

     

使用基于队列的并发类型与performBlock:和performBlockAndWait结合使用上下文:。

Apple Docs

作为旁注,你得到的错误信息是仍然站在Cocoa内的最后几个“复活节彩蛋”之一。

答案 1 :(得分:1)

构建iOS 9.0时不再出现此问题。