CoreData异步提取会导致并发调试程序错误

oly*_*ise 13 concurrency multithreading core-data ios

我正在使用

-com.apple.CoreData.ConcurrencyDebug
Run Code Online (Sandbox Code Playgroud)

在我的CoreData应用程序中启动以调试并发性的论点.

在应用程序启动期间,我在主线程的托管对象上下文中执行异步提取.

// set up the async request
   NSError * error = nil;
        [MOC executeRequest:asyncFetch error:&error];
        if (error) {
            NSLog(@"Unable to execute fetch request.");
            NSLog(@"%@, %@", error, error.localizedDescription);
        }
Run Code Online (Sandbox Code Playgroud)

从主线程调用此代码,但executeRequest:将其排入另一个线程,我理解这是正确的行为.

并发调试器不喜欢这样,说(我估计)我在这里做错了.我也尝试将[MOC performBlock:]其包装在其中也有效,但也会导致多线程违规.在这两种情况下,我得到这个:

[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__
Run Code Online (Sandbox Code Playgroud)

我是否错误地使用异步提取,或者并发调试器在这里是错误的?

编辑:我也尝试将其包装在MOC中performBlock,这应该确保从主线程调用它.在任何情况下,调用都从主线程入队,但在其他地方执行.

它说fetch已从主线程中排队,但它似乎实际上发生在另一个上.

编辑:这是获取请求:

 NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"MyEntity"];

 NSPredicate * pred = [NSPredicate predicateWithFormat:@"boolProperty == YES"];
    fetchRequest.predicate = pred;
 NSSortDescriptor * sort = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
 fetchRequest.sortDescriptors = @[sort];      fetchRequest.propertiesToFetch = @[@"prop1", @"prop2", @"prop3", @"prop4"];

 NSPersistentStoreAsynchronousFetchResultCompletionBlock resultBlock = ^(NSAsynchronousFetchResult *result) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [[NSNotificationCenter defaultCenter] postNotificationName:kFetchCompleteNotification object:result];
        });
    };

 NSAsynchronousFetchRequest *asyncFetch = [[NSAsynchronousFetchRequest alloc]
                                              initWithFetchRequest:fetchRequest
                                              completionBlock:resultBlock];
Run Code Online (Sandbox Code Playgroud)

然后我收到通知的结果:

- (void)fetchCompletedNote:(NSNotification *)note {
    NSAsynchronousFetchResult * result = note.object;
    if (![cachedResults isEqualToArray:result.finalResult]){
        cacheResults = result.finalResult;
        [self.collectionView reloadData];
    }
}
Run Code Online (Sandbox Code Playgroud)

jos*_*p04 6

我认为这是Apple的错误.

我提交了错误报告:https: //openradar.appspot.com/30692722

并添加了重现问题的示例项目:https: //github.com/jcavar/examples/tree/master/TestAsyncFetchCoreData

另外,如果你不想禁用只是因为这个问题的标志,你可能要调酒__Multithreading_Violation_AllThatIsLeftToUsIsHonor__的方法,NSManagedObjectContext只是这部分代码.您需要在执行请求后恢复该操作,以便在实际问题中出现违规行为.

  • 我正在把这头发拉出来.通过我的代码逐步显示我在主线程上,但并发调试显示CoreData` + [NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__]: (2认同)

Mar*_*rra 5

并发调试器告诉您您正在MOC从错误的线程/队列访问。您只能调用-executeRequest: error:上下文所属的线程/队列。如果这是一个,NSMainQueueConcurrencyType那么你需要在主线程上。否则,如果它是NSPrivateQueueConcurrencyType您需要使用-performBlock:-performBlockAndWait:在正确的队列上运行执行。

我添加了一个截图,见上文。请求从主线程排队,但在另一个线程上执行。

好的,有几件事:

  1. 那是断线/崩溃的线路还是您看到错误输出?
  2. 您的错误处理不正确。您应该查看结果,-executeRequest: error:如果结果是,nil则您处于错误状态。即使成功,也可以填充错误变量。

我注意到您在屏幕截图中发布的代码与您之前发布的代码不同。您-performBlock:最初是添加还是不包含它?

  • 这似乎是并发调试选项的错误,或者它可能没有更新以解决异步获取请求。在我自己的测试中,陷阱发生在具有 Core Data 内部方法调用堆栈的线程上。如果我删除调试标志,则将按预期在主线程上调用完成块。 (4认同)