Potential reference count issues unless grabbing f

2019-03-05 23:31发布

问题:

I have a second question after reading Marcus S. Zarra's (excellent) Core Data: Data Storage and Management for iOS, OS X, and iCloud (2nd edition) if I may.

The book's section Asynchronously Adding the NSPersistentStore contains this piece of code (excerpt):

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

    // ...

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

    // ...
});

It also contains this explanation:

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.

What is the nature of this potential reference count issue?

I understand that if the dispatched block would refer to a NSPersistentStoreCoordinator that is scoped outside, it would retain that coordinator (increase its reference count by one), which then could be released only after the blocks has finished execution. If the background thread never executed or if it would not terminate, a reference count issue would remain.

Is that all there is to it or are there more subtle cases that would also constitute reference count issues and that could materialize in this situation?

As it stands, I would not be (significantly) concerned about a potential reference count issue in this particular case (simple background operation that is dispatched for immediate execution) but maybe I am missing something.

回答1:

The block itself could be executed relatively late in this example (a lot of other code could execute before this block). Which means much can happen to the context or the store coordinator and hypothetically the store coordinator is not even the same object before and after the block starts executing.

By calling the manager to retrieve the new reference for the coordinator you ensure first that you will get the latest coordinator as well as you keep the current coordinator unretained from the block. If you were to reuse the coordinator from outside the block that coordinator will be retained and may produce (although unlikely) issues such as memory inflating. And if all goes bad and the block is never even executed the coordinator is simply retained forever and you have a memory leak.

This is just a good practice.