核心数据并发`performBlockAndWait:`NSManagedObjectContext zombie [英] Core Data concurrency `performBlockAndWait:` NSManagedObjectContext zombie

查看:135
本文介绍了核心数据并发`performBlockAndWait:`NSManagedObjectContext zombie的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从已发布的应用程式中收到以下当机报告:





synchronizeMyWords 方法从数据库获取实体,使用主上下文父级创建私有队列上下文,最后保存结果。所有操作都在后台线程中。这个方法在每次应用程序进入后台前台时调用。这是一个简化的方法:

   - (AWSTask *)synchronizeMyWords {
__weak typeof(self)weakSelf = self;

AWSContinuationBlock block = ^ id _Nullable(AWSTask * _Nonnull task){
if([task.result isKindOfClass:[NSArray class]]){
NSArray * records = *)task.result;
NSManagedObjectContext * context = [NSManagedObjectContext MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]];
[context performBlockAndWait:^ {
for(NSDictionary * records in records){
[RDRWord MR_createEntityInContext:context];
}

[context save:nil];
}];
return [AWSTask taskWithResult:@YES];
}
return [AWSTask taskWithError:[NSError errorWithDomain:@code:404 userInfo:nil]];
};

AWSExecutor * executor = [AWSExecutor defaultExecutor];


return [[self loadLocalWords] continueWithExecutor:executor withBlock:block];
}

正如你看到的,我使用 Magical Record 第三方库来管理核心数据堆栈。下面是创建私有队列上下文的方法:

  +(NSManagedObjectContext *)MR_contextWithParent:(NSManagedObjectContext *)parentContext 
{
NSManagedObjectContext * context = [self MR_newPrivateQueueContext];
[context setParentContext:parentContext];
[context MR_obtainPermanentIDsBeforeSaving];
return context;
}



您可以检查整个 NSManagedObjectContext + MagicalRecord github上的类别此处



上下文中的对象 performBlockAndWait: code>释放之前它逃避范围?
我个人不能重现崩溃,但很多我的用户(iOS 8.1 - 10设备)受此问题影响。



更新1:



=http://www.jamieq.com/blog/2013/09/02/a-frustrating-nsmanagedobjectcontext-lifecyle-bug/ =nofollow noreferrer>博客

$ b $核心数据提供了丰富的API来处理后台线程。

这些也可以通过魔法记录访问。



看起来你不必要地创建太多的线程。我认为使用 AWSContinuationBlock AWSExecutor 不是一个好主意。 synchronizeMyWords 可以从后台线程调用。该块可能在后台线程上运行。在块中创建一个新的后台线程链接到子上下文。不清楚 loadLocalWords 返回或 continueWithExecutor:block:如何处理线程。



保存数据也有问题。保存子上下文后,不保存主上下文;这可能是后来发生的,但也许是与其他操作有关,所以你的代码在之前工作的事实可能更多是一个假阳性。



我的建议是简化线程代码。你应该把自己局限于Core Data块API。


I have a following crash report from my released app:

synchronizeMyWords method fetches the entities from database, creates private queue context with main context parent and finally saves results. All operations are in the background thread. This method being called every time app goes into background and foreground. Here is a simplified method:

- (AWSTask *)synchronizeMyWords {
  __weak typeof(self) weakSelf = self;

  AWSContinuationBlock block = ^id _Nullable(AWSTask * _Nonnull task) {
    if ([task.result isKindOfClass:[NSArray class]]) {
      NSArray * records = (NSArray *)task.result;
      NSManagedObjectContext * context = [NSManagedObjectContext MR_contextWithParent:[NSManagedObjectContext MR_defaultContext]];
      [context performBlockAndWait:^{
        for (NSDictionary * info in records) {
            [RDRWord MR_createEntityInContext:context];
        }

        [context save:nil];
      }];
      return [AWSTask taskWithResult:@YES];
    }
    return [AWSTask taskWithError:[NSError errorWithDomain:@"" code:404 userInfo:nil]];
  };

  AWSExecutor * executor = [AWSExecutor defaultExecutor];


  return [[self loadLocalWords] continueWithExecutor:executor withBlock:block];
}

As you see I am using Magical Record 3rd party library to manage Core Data stack. Here is a method of creating private queue context:

+ (NSManagedObjectContext *) MR_contextWithParent:(NSManagedObjectContext *)parentContext
{
    NSManagedObjectContext *context = [self MR_newPrivateQueueContext];
    [context setParentContext:parentContext];
    [context MR_obtainPermanentIDsBeforeSaving];
    return context;
}

You can check the whole NSManagedObjectContext+MagicalRecord category on github here.

How is it available that context object inside performBlockAndWait: released before it escapes the scope? I am personally not able to reproduce the crash, but a lot of my users (iOS 8.1 - 10 devices) are affected by this issue.

UPDATE 1:

Here is for instance same report on blog

解决方案

Core Data provides ample APIs to deal with background threads. These are also accessible via Magical Record.

It looks as if you creating too many threads unnecessarily. I think that the employment of AWSContinuationBlock and AWSExecutor is not a good idea. synchronizeMyWords could be called from a background thread. The block might be run on a background thread. Inside the block you create a new background thread linked to the child context. It is not clear what loadLocalWords returns, or how continueWithExecutor:block: deals with threads.

There is also a problem with the saving of the data. The main context is not saved after the child context is saved; presumably this happens later, but perhaps in connection with some other operation, so that the fact that your code was working before is perhaps more of a "false positive".

My recommendation is to simplify the threading code. You should confine yourself to the Core Data block APIs.

这篇关于核心数据并发`performBlockAndWait:`NSManagedObjectContext zombie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆