【发布时间】:2017-03-30 11:24:47
【问题描述】:
我正在处理一个奇怪的案例。我从 API 获取一些数据,将响应 JSON 转换为 NSManagedObjects 并保存它们,所有这些都在后台线程中并使用父级为 NSMainQueueConcurrencyType 的 NSPrivateQueueConcurrencyType 上下文。
在创建 NSManagedObjects 的同时,我将它们放在一个数组中,以便通过在主线程上执行的完成块在我的视图控制器中使用它。这是我正在做的简化版本。
- (void)getObjectFromAPIWithCompletion:((^)(NSArray *objects, NSError *error))completion
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSManagedObjectContext *backgroundMoc = [[CoreDataStack sharedManager] newChildContextWithConcurrencyType:NSPrivateQueueConcurrencyType];
NSArray *items = [self processToParseResponseFromAPIAndSaveInCoreDataUsingContext:backgroundContext];
[backgroundMoc save:nil];
dispatch_async(dispatch_get_main_queue(), ^{
//Beyond this point, all properties of items are nil or 0 (if integer)
if(completion) completion(items, error);
});
});
}
奇怪的事情发生在完成块内部。我在该块的第一行放置了一个断点并在控制台上打印items 数组。一切看起来都很好,所有项目(在本例中为 50 个)及其属性都正常。
问题是,在那一行之后(我没有更改 items 数组上的任何内容)所有对象都变成错误并且我没有获得任何有关属性的数据。
不知道这种罕见行为的原因是什么。有什么想法吗?
谢谢。
编辑:Hal 的回答让我走上了正轨,所以这就是我为解决这个问题所做的工作。就在调用将在主线程上执行的块之前,我将托管对象从后台上下文“移动”到主上下文,并使用它们的 objectID 获取。像这样:
NSArray *objects = //Objects created on background thread with Private queue
NSMutableArray *objectsIDs = [NSMutableArray array];
for (Object *object in object) {
[objectsIDs addObject:object.objectID];
}
//Save on private managed object context and on completion...
[self.managedObjectContext saveWithCompletion:^(NSError *error) {
NSManagedObjectContext *mainMOC = [[CoreDataManager sharedManager] mainContext];
NSMutableArray *fetchedObjects = [NSMutableArray array];
for (NSManagedObjectID *objectID in objectsIDs) {
[fetchedArticles addObject:[mainMOC objectWithID:objectID]];
}
if (completion) completion(fetchedObjects, pagination, nil);
}];
这样,所有对象都不是主线程上的故障。
【问题讨论】:
标签: ios objective-c multithreading core-data