Re: Core Data, transient ivars and undo
Re: Core Data, transient ivars and undo
- Subject: Re: Core Data, transient ivars and undo
- From: Andre <email@hidden>
- Date: Tue, 14 Feb 2006 10:00:45 -0800
On 平成 18/02/14, at 1:03, Christiaan Hofman wrote:
On 14 Feb 2006, at 10:27 AM, email@hidden wrote:
On 平成 18/02/13, at 6:43, Christiaan Hofman wrote:
On 13 Feb 2006, at 1:09 AM, email@hidden wrote:
Christiaan Hofman wrote:
I am very much confused about undo in Core Data, in particular
when it comes to "transient" values and other dependent state
information. AFAICS the transient value or state info is not
updated in any way in undo, which can easily lead to
inconsistent states in CD apps. How should I handle this in
general?
For example a "transient" value stored in an ivar. Eg for a non-
standard attribute, which is stored in the MOC as data, but has
an ivar representation in a NSManagedObject subclass. Usually,
you interact with the transient value (ivar) rather than the
underlying CD value. However it is the data in the MOC that is
changed in undo, and only that. So you get an inconsistent
state. Writing (KVC compliant) accessors for the underlying
data does not help, as they are not called by undo.
In the docs and example projects like CoreRecipes many
accessors seem to have this flaw. Eg the "bounds" example in
"Non-Standard Attributes" section of the Core Data Programming
Guide. Here the bounds ivar and the boundsAsData atribute
should always be synchronized. However, AFAICS, if I would undo
setting (changing) the bounds, only the boundsAsData attribute
is changed, giving me an inconsistent state. This seems to me a
bug in CD, or at least in the docs and the examples, as nothing
is mentioned about it.
Perhaps [self setKey:@"boundsAsData"
triggerChangeNotificationForDependentKeys:[NSArray
arrayWithObject:@"bounds"]] ?
Since, bounds is not "known" by core data that it is related to
boundsAsData, it needs to be told they are, I beleive that
telling core data to generate a change note when boundsAsData
changes to also notify observers of the change to bounds, would
call the getter in your bounds method, and reverse the
change.... have you tried this?
No, this would not work. This way just observers are told that
bounds has changed as well, however the actual value of the ivar
bounds has not changed, which is the real problem. When the
getter is called the stale value for bounds is found and
returned. No new value is generated as it was not reset (note
that it is only regenerated when it has the proper zero value,
otherwise it would always be regenerated).
I see, how about in the boundsAsData method, override it to also
reset the cached value of bounds so that the next time bounds is
called, the cached value is non-existent, then it can regenerate
the cache and return it the next time bounds is called? Would that
work?
The question is: where should the cached (derived) data be reset?
You seem to suggest here to do it in he getter, but that is
equivalent to recalculating the derived data every time, making the
cache useless, and this can become very inefficient (note that the
getter cannot know if it was called after it was invalidate unless
it was already invalidated). Doing this in a setter will not work,
as undo does not call those. KVO dependent keys don't call
anything, they merely notify, so they cannot invalidate the data
either. I don't see any other way than KVO observing.
I see... here was what I was thinking. In the setter for
boundsAsData, set the value of (cached) bounds (setting the variable
directly) to nil. Then, only if the value of the cached bounds is
nill, it (the bounds getter) recalculates from the derived value and
sets the cache (directly, not using KVC), otherwise it simply calls
the cached value. If there are any observers of bounds, then the
dependent key notification will let those observers know that when
boundsAsData changed, also bounds is changed, and they will pull the
data from bounds. If there are no observers, then its OK if the
bounds cache is stale, since its nil, only the first time its called,
bounds is recalculated from the derived value, then subsequent calls
are from the cache, as long as the cache is non-nil. It should be
pretty effecient....KVB/KVO basically encourages the lazy/deferred
approach to data management AFIACS.
BTW, in the actual example in the docs undo would work properly,
as bounds is declared as a transient value in the MOM (even
though the primitiveValue is not used, CD is smart enough to find
the ivar). However I am asking about a situation where this is
not, for example if the type is not of a KVC compliant type. Note
that this is just a very simple version of a more general
problem, where there can be more complex state information
depending on the managed data. E.g. the contents of a smartgroup
has to be regenerated when the (managed) predicateData changes
through undo, but you definitely don't want to regenerate this
every time someone asks for it.
Christiaan
So my question is: how should I handle dependent state
information in general so that undo works properly? Do I need
to observe MOM keys for values on which the state of some
object depends? Or should I explicitly register undo operations
when I change an ivar such as the bounds in the example? It
would have been helpful (I would even say required) that these
issues were mentioned in the docs, especially as undo is
automatic with little information and control about what's
going on behind the scene.
I think setKey: triggerChangeNotificationForDependentKeys may be
your answer. Called in +initialize it may work for your
particular difficulty.
Christiaan
_______________________________________________
MacOSX-dev mailing list
email@hidden
http://www.omnigroup.com/mailman/listinfo/macosx-dev
Andre
email@hidden
Christiaan
_______________________________________________
MacOSX-dev mailing list
email@hidden
http://www.omnigroup.com/mailman/listinfo/macosx-dev
Andre
email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden