Archive for February 28, 2015

Saturday, February 28, 2015 [Tweets] [Favorites]

Core Data vs. ARC

Matt Drance:

1) Create NSManagedObjectContext

2) Fetch

2) Pass results to a method

I’ve seen ARC kill the MOC before line 3.

With at-autoreleasepool, you could optimize given advanced knowledge. Now you need advanced knowledge to not die.

The problem here is that Core Data expects that you will keep the managed object context alive as long as you are using any of its objects, but the objects do not retain their context:

Managed objects know what managed object context they’re associated with, and managed object contexts know what managed objects they contain. By default, though, the references between a managed object and its context are weak. This means that in general you cannot rely on a context to ensure the longevity of a managed object instance, and you cannot rely on the existence of a managed object to ensure the longevity of a context.

ARC will try to release the context after the last line of code that references it, even if this is before the end of the scope. (This is different from other automated reference counting systems, such as Python’s.) It doesn’t know that later code in that scope may use managed objects that assume their context is still alive. This was also a problem with Objective-C garbage collection; Core Data used weak references even though the collector could have cleaned up cyclic strong ones.

Some potential solutions:

All of this makes me sad because something this basic should not be so error-prone, and it should not be getting worse with time. As Drance notes, all of this just worked with manual reference counting. An autoreleased context would automatically stay alive as long as it was needed. You could fine-tune object lifetimes for increased performance; now you have to do so to avoid crashes.

Arguably, this is a design flaw in Core Data rather than ARC. Why don’t objects retain their context?

As far as I can tell, the situation is actually worse with Swift. It uses ARC but doesn’t seem to have the equivalent of NS_VALID_UNTIL_END_OF_SCOPE.