核心数据并发`performBlockAndWait:`的NSManagedObjectContext僵尸

问题描述 投票:0回答:2

我从发布应用程序后面的崩溃报告:

enter image description here

synchronizeMyWords方法从数据库中获取的实体,创建了主背景父私有队列背景下,最终节省了结果。所有操作都是在后台线程。这种方法被称为每次应用程序进入backgroundforeground。下面是一个简化的方法:

- (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];
}

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

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

您可以检查在github NSManagedObjectContext+MagicalRecord整个here类别。

它里面提供的是context对象performBlockAndWait:如何释放它避开范围过吗?我个人无法重现崩溃,但我的很多用户(的iOS 8.1 - 10设备)都受此问题的影响。

更新1:

下面是对blog例如同一报告

ios objective-c core-data magicalrecord aws-sdk-ios
2个回答
1
投票

核心数据提供了充足的API来处理后台线程。这些也都是通过神奇的记录访问。

这看起来好像你创建线程太多不必要的。我认为AWSContinuationBlockAWSExecutor的就业是不是一个好主意。 synchronizeMyWords可以从后台线程调用。该块可能会在后台线程中运行。块中创建链接到子上下文创建新的后台线程。目前尚不清楚是什么loadLocalWords回报,或如何与线程continueWithExecutor:block:交易。

还有与数据的保存问题。主要背景的孩子上下文被保存后不保存;想必这种情况发生后,但可能与一些其它操作连接,这样的事实,你的代码是之前的工作也许是多了一个“假阳性”的。

我的建议是简化线程代码。你应该把自己定格在核心数据块的API。


2
投票

标志着我@Mundi的答案是正确的,因为他写的,你应该遵循的一般方法。现在,我想在这里分享我如何调试它。首先,我了解到,它可在Xcode打开调试并发断言。您需要将下面就启动参数:

-com.apple.CoreData.ConcurrencyDebug 1

enter image description here

现在,在您的应用程序的输出,你应该可以看到日志消息:

2016-12-12 01:58:31.665 your-app[4267:2180376] CoreData: annotation: Core Data multi-threading assertions enabled.

当我打开它,我的应用程序在synchronizeMyWords方法(老实说,不仅在那里。想知道,为什么苹果不包括默认情况下在调试模式下的并发断言?)坠毁。我检查defaultExecutorAWSCore library什么,看到这个:

+ (instancetype)defaultExecutor {
    static AWSExecutor *defaultExecutor = NULL;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        defaultExecutor = [self executorWithBlock:^void(void(^block)()) {
            // We prefer to run everything possible immediately, so that there is callstack information
            // when debugging. However, we don't want the stack to get too deep, so if the remaining stack space
            // is less than 10% of the total space, we dispatch to another GCD queue.
            size_t totalStackSize = 0;
            size_t remainingStackSize = remaining_stack_size(&totalStackSize);

            if (remainingStackSize < (totalStackSize / 10)) {
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
            } else {
                @autoreleasepool {
                    block();
                }
            }
        }];
    });
    return defaultExecutor;
}

根据他们的说法if,我continuationBlock不保,要在DISPATCH_QUEUE_PRIORITY_DEFAULT队列执行。所以,我创建一个共享dispatch_queue_t排队,并呼吁其与performBlockAndWait: CoreData相结合的方法的所有操作。其结果是,现在有没有崩溃,我提交了新的版本。我会更新这个帖子,如果我没有得到与context僵尸任何崩溃报告。

© www.soinside.com 2019 - 2024. All rights reserved.