潜在的引用计数问题,除非在后台线程中获取新的引用

Potential reference count issues unless grabbing fresh reference in background thread

如果可以的话,我有一个 question after reading Marcus S. Zarra's (excellent) Core Data: Data Storage and Management for iOS, OS X, and iCloud(第 2 版)。

本书的Asynchronously Adding the NSPersistentStore部分包含这段代码(摘录):

dispatch_queue_t queue;
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{

    // ...

    NSPersistentStoreCoordinator *coordinator = nil;
    coordinator = [[self managedObjectContext] persistentStoreCoordinator];

    // ...
});

里面还有这样的解释:

The reason we grab a fresh reference to the NSPersistentStoreCoordinator is one of safety. If we were to use the reference from the outer method, we would be incrementing the retain count of the NSPersistentStoreCoordinator and potentially causing an unnecessary reference count issue.

这个潜在的引用计数问题的性质是什么?

我知道如果分派的块将引用范围外的 NSPersistentStoreCoordinator,它将保留该协调器(将其引用计数增加一),然后只有在块完成后才能释放协调器执行完毕。如果后台线程从未执行过或不会终止,则引用计数问题将仍然存在。

仅此而已,还是有更微妙的情况也构成引用计数问题并且可能在这种情况下出现?

就目前而言,我不会(非常)担心这种特殊情况下的潜在引用计数问题(为立即执行而分派的简单后台操作),但也许我遗漏了一些东西。

在此示例中,块本身可能执行得相对较晚(许多其他代码可能在此块之前执行)。这意味着上下文或存储协调器可能会发生很多事情,并且假设存储协调器在块开始执行之前和之后甚至不是同一个对象。

通过调用管理器检索协调器的新引用,您首先确保您将获得最新的协调器,并确保当前协调器不保留在块中。如果您要从块外部重用协调器,协调器将被保留并可能产生(尽管不太可能)内存膨胀等问题。如果一切都变坏并且块甚至从未执行过,协调器将永远保留并且内存泄漏。

这只是一个很好的做法。