willTurnIntoFault being called more than once, resulting in crash
-
27-09-2019 - |
문제
In a subclass of NSManagedObject
my overridden implementation of willTurnIntoFault
is being called twice when undoing some code which originally created the object in question. This results in a crash when attempting to double-unregister for KVO on a key path.
The Apple documents say this is the right place to un-register for KVO.
A bit of context - the undo operation involves removing the corresponding view of the model from it's superview. The view retains it's model.
So my question is: what kind of programmer errors can result in willTurnIntoFault
being called twice in a subclass of NSManagedObject
?
Note: Previously I was overriding dealloc
in this class but have since realised this is not recommended for subclasses of NSManagedObject. I've since moved this code into -didTurnIntoFault
. I'm not currently overriding any other methods which the Apple docs say you should not override.
해결책 2
Seems the issue was caused by a custom setter method which was setting/unsetting KVO values from within willTurnIntoFault.
다른 팁
For posterity's sake: I had the same problem. In my case I had an object A with a (to-one) relation to an object B. When A got deleted B's inverse relation to A was set to null
. This caused B's observeValueOfKeyPath:ofObject:change:context
method to be invoked (where keypath
was B's relation to A). Unfortunately this method checked a property of A, causing the faulting of A to be cancelled (note that in this situation awakeFromFetch
does not get called--I presume because the object never actually did get to fault state). Hence I might might get a second call to willTurnIntoFault
later and the object would try to unregister for KVO again, resulting in a crash--just like in the OP.
For me the solution was to change the delete rule for A to cascade, so that the B object got deleted when the A object got deleted AND to unregister for KVO in prepareForDeletion
. This is important because the deletion of A will still cause B's inverse relation to be set to nil before B is actually deleted.
Note that prepareForDeletion
gets called before but not instead of willTurnIntoFault
. Hence, if you unregister for KVO in both, you need to maintain some state to make sure you have not already unregistered.