Core Data concurrency `performBlockAndWait:` NSManagedObjectContext zombie

后端 未结 2 1906
一向
一向 2021-01-26 11:58

I have a following crash report from my released app:

synchronizeMyWords method fetches the entities from database, creates private queue context w

2条回答
  •  暗喜
    暗喜 (楼主)
    2021-01-26 12:08

    I marked @Mundi answer as correct, because he wrote the general approach you should follow. Now, I want to share here how I debugged it. Firstly, I learned that, it is available to turn on debug concurrency assertion in xcode. You need to pass following argument on launch:

    -com.apple.CoreData.ConcurrencyDebug 1

    Now, in your application output, you should see log message:

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

    Once I turned it on, my app crashed in synchronizeMyWords method (honestly, not only there. Wondering, why Apple does not include concurrency assertions by default in debug mode?). I checked what defaultExecutor is in AWSCore library and saw this:

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

    According to their if statement, my continuationBlock was not guaranteed to be executed on DISPATCH_QUEUE_PRIORITY_DEFAULT queue. So, I created one shared dispatch_queue_t queue and call all operations on it combining with performBlockAndWait: CoreData method. As a result, there are no crashes now and I submitted new release. I will update this post, if I do not get any crash report with context zombie.

提交回复
热议问题