I was experimenting recently with implementing a doubly linked list in Core Data as a means to store ordered relationships and discovered a rather gnarly problem. It's summarised in the title of this post, but what does that actually mean?
Let's imagine you've got an entity with a one-to-one relationship to itself.
So you can easily construct a chain of
Foos, and move from one to another using
-previousFoo. When calling
-setPreviousFoo: Core Data very kindly maintains the other side of the relationship for you.
The problem comes while undoing or redoing a change to the relationship and you are observing the relationship, perhaps for display in the UI. Let's say you're redoing an operation that connects two
Foos together. The order of operations will be something like this:
[foo1 setPrimitiveNextFoo:foo2]; [foo1 didChangeValueForKey:@"nextFoo"]; [foo2 willChangeValueForKey:@"previousFoo"]; [foo2 setPrimitivePreviousFoo:foo1]; [foo2 didChangeValueForKey:@"previousFoo"];
The issue here is that anything observing the
nextFoo property of
foo1 will be notified of the change before
previousFoo has been updated to match. The only way to know when the relationship is back in a consistent state is to then observe
If only the Core Data team had made life more pleasant by doing something more like this:
[foo1 willChangeValueForKey:@"nextFoo"]; [foo2 willChangeValueForKey:@"previousFoo"]; [foo1 setPrimitiveNextFoo:foo2]; [foo2 setPrimitivePreviousFoo:foo1]; [foo1 didChangeValueForKey:@"nextFoo"]; [foo2 didChangeValueForKey:@"previousFoo"];
Then any object observing either property will only be notified once the change is complete. Oh well.