【问题标题】:NSManagedObjects created on background turning into faults on main thread在后台创建的 NSManagedObject 变成了主线程上的错误
【发布时间】: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


    【解决方案1】:

    如果这些对象(items 的内容)已经在后台线程中创建,则不能在主线程中使用它们。您不能在线程之间传递 NSManagedObject 实例。

    您必须传递 NSManagedObjectID(在您保存后台 MOC 之前它不会是永久性的),或者在主线程上使用 NSFetchedResultsController(指向主 MOC)。这是 NSFetchedResultsController 设计的一种情况,所以我建议你走这条路。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-26
      • 1970-01-01
      • 2012-01-08
      • 1970-01-01
      相关资源
      最近更新 更多