Core Data Confusion

  • For the last couple of weeks I have been navigating through the Core
    Data swamp and have made significant progress in my understanding of
    the architecture.  That said, there are a couple of things that
    really have me shaking my head, and I would appreciate a second look.

    Real quick: my application is intended to track information about
    animals on different farms.  The data model has three entities:

    - FARM <-->> ANIMAL <-->> VACCINATION

    Note the relationships between each entity are to-many going in the
    right direction and to-one going in the left (inverse) direction.  A
    farm can contain many animals and each animal can have multiple
    vaccinations.

    Without getting into too much detail, the FARM entity has a transient
    property report(a string) which depends on other attributes in the
    FARM entity changes.  So the initialize method in my FARM Managed
    Object class is:

    + (void)initialize
    {
    [self setKeys:[NSArray arrayWithObjects:
              @"farmName",
              @"managerName",
              nil]
        triggerChangeNotificationsForDependentKey:@"report"];
    }

    The attributes farmName and managerName are updated in text fields in
    a window and are updated daily.  The idea is that when either of
    these values change, the report attribute should be updated to
    reflect changes to the names.  My report method:

    - (NSString *)report
    {
        NSString * tmpValue = nil;

        [self willAccessValueForKey: @"report"];
    tmpValue = [self constructFarmReport];
        [self didAccessValueForKey: @"report"];

        return tmpValue;
    }

    - (NSString *)constructFarmReport
    {
    NSString *reportString = [[NSString alloc] initWithString:@""];
    NSString *farm = [self primitiveValueForKey:@"farmName"];
    NSString *manager = [self primitiveValueForKey:@"managerName"];
    ...

    When the report method is called due to a change in farmName/
    managerName, it will call constructFarmReport which builds the report
    string and returns it.  Note that I am using the method
    primitiveValueForKey to access the values farmName/managerName
    instead of accessing the identifiers directly.  I've found that in
    the debugger, if I don't use primitiveValueForKey, then the
    willAccessValueForKey/didAccessValueForKey methods get invoked.  My
    question is: is using the primitive method to obtain the values of
    these attributes a bad thing?  I know the Core Data document
    discourages one from using the primitive version of the call, and
    encourages use of either valueForKey: or access the identifier
    directly, but if control is already in a method which was invoked
    BECAUSE of KVO, is accessing that variable again INSIDE of the
    observed method a bad thing?
    --
    Boisy G. Pitre
    337.781.3570 mobile
    email: <boisy...>
    Website: www.boisypitre.com

    "If there is truth to the proposition that knowing the past helps us
    to understand the present, I believe there is at least as much truth
    to the proposition that what we know of the present is crucial to our
    understanding of the past.  What we have not ourselves experienced or
    observed we can at most only partially and imperfectly comprehend;
    and I suspect that there is much in history that is so remote from
    our own experiences or observations as to be largely beyond our
    understanding." - Kenneth M. Stamp
  • Short answer is no

    It is not a bad thing to be accessing the primitive values in this
    situation.  I believe that warning was for external access to the
    values.  e.g. object A should be calling -getValueForKey: instead of -
    getPrimitiveValueForKey: on object B.  This ensures that object B has
    complete control over what happens when that value is accessed.

    Marcus S. Zarra
    Zarra Studios LLC
    Simply Elegant Software for OS X
    www.zarrastudios.com

    On Jan 31, 2007, at 10:32 AM, Boisy Pitre wrote:

    > For the last couple of weeks I have been navigating through the
    > Core Data swamp and have made significant progress in my
    > understanding of the architecture.  That said, there are a couple
    > of things that really have me shaking my head, and I would
    > appreciate a second look.
    >
    > Real quick: my application is intended to track information about
    > animals on different farms.  The data model has three entities:
    >
    > - FARM <-->> ANIMAL <-->> VACCINATION
    >
    > Note the relationships between each entity are to-many going in the
    > right direction and to-one going in the left (inverse) direction.
    > A farm can contain many animals and each animal can have multiple
    > vaccinations.
    >
    > Without getting into too much detail, the FARM entity has a
    > transient property report(a string) which depends on other
    > attributes in the FARM entity changes.  So the initialize method in
    > my FARM Managed Object class is:
    >
    > + (void)initialize
    > {
    > [self setKeys:[NSArray arrayWithObjects:
    > @"farmName",
    > @"managerName",
    > nil]
    > triggerChangeNotificationsForDependentKey:@"report"];
    > }
    >
    > The attributes farmName and managerName are updated in text fields
    > in a window and are updated daily.  The idea is that when either of
    > these values change, the report attribute should be updated to
    > reflect changes to the names.  My report method:
    >
    > - (NSString *)report
    > {
    > NSString * tmpValue = nil;
    >
    > [self willAccessValueForKey: @"report"];
    > tmpValue = [self constructFarmReport];
    > [self didAccessValueForKey: @"report"];
    >
    > return tmpValue;
    > }
    >
    >
    > - (NSString *)constructFarmReport
    > {
    > NSString *reportString = [[NSString alloc] initWithString:@""];
    > NSString *farm = [self primitiveValueForKey:@"farmName"];
    > NSString *manager = [self primitiveValueForKey:@"managerName"];
    > ...
    >
    > When the report method is called due to a change in farmName/
    > managerName, it will call constructFarmReport which builds the
    > report string and returns it.  Note that I am using the method
    > primitiveValueForKey to access the values farmName/managerName
    > instead of accessing the identifiers directly.  I've found that in
    > the debugger, if I don't use primitiveValueForKey, then the
    > willAccessValueForKey/didAccessValueForKey methods get invoked.  My
    > question is: is using the primitive method to obtain the values of
    > these attributes a bad thing?  I know the Core Data document
    > discourages one from using the primitive version of the call, and
    > encourages use of either valueForKey: or access the identifier
    > directly, but if control is already in a method which was invoked
    > BECAUSE of KVO, is accessing that variable again INSIDE of the
    > observed method a bad thing?
    > --
    > Boisy G. Pitre
    > 337.781.3570 mobile
    > email: <boisy...>
    > Website: www.boisypitre.com
    >
    > "If there is truth to the proposition that knowing the past helps
    > us to understand the present, I believe there is at least as much
    > truth to the proposition that what we know of the present is
    > crucial to our understanding of the past.  What we have not
    > ourselves experienced or observed we can at most only partially and
    > imperfectly comprehend; and I suspect that there is much in history
    > that is so remote from our own experiences or observations as to be
    > largely beyond our understanding." - Kenneth M. Stamp
    >
    >
    >
    > _______________________________________________
    > MacOSX-dev mailing list
    > <MacOSX-dev...>
    > http://www.omnigroup.com/mailman/listinfo/macosx-dev
  • On Feb 2, 2007, at 2:05 PM, Marcus S. Zarra wrote:

    > It is not a bad thing to be accessing the primitive values in this
    > situation.  I believe that warning was for external access to the
    > values.  e.g. object A should be calling -getValueForKey: instead
    > of -getPrimitiveValueForKey: on object B.  This ensures that object
    > B has complete control over what happens when that value is accessed.

    What do you think about the fact that -primitiveValueForKey isn't
    wrapped in will/did accessValueForKey? That seems like it could cause
    some bizarre behavior.

        - Scott
  • On 31 Jan 2007, at 6:32 PM, Boisy Pitre wrote:

    > For the last couple of weeks I have been navigating through the
    > Core Data swamp and have made significant progress in my
    > understanding of the architecture.  That said, there are a couple
    > of things that really have me shaking my head, and I would
    > appreciate a second look.
    >
    > Real quick: my application is intended to track information about
    > animals on different farms.  The data model has three entities:
    >
    > - FARM <-->> ANIMAL <-->> VACCINATION
    >
    > Note the relationships between each entity are to-many going in the
    > right direction and to-one going in the left (inverse) direction.
    > A farm can contain many animals and each animal can have multiple
    > vaccinations.
    >
    > Without getting into too much detail, the FARM entity has a
    > transient property report(a string) which depends on other
    > attributes in the FARM entity changes.  So the initialize method in
    > my FARM Managed Object class is:
    >
    > + (void)initialize
    > {
    > [self setKeys:[NSArray arrayWithObjects:
    > @"farmName",
    > @"managerName",
    > nil]
    > triggerChangeNotificationsForDependentKey:@"report"];
    > }
    >
    > The attributes farmName and managerName are updated in text fields
    > in a window and are updated daily.  The idea is that when either of
    > these values change, the report attribute should be updated to
    > reflect changes to the names.  My report method:
    >
    > - (NSString *)report
    > {
    > NSString * tmpValue = nil;
    >
    > [self willAccessValueForKey: @"report"];
    > tmpValue = [self constructFarmReport];
    > [self didAccessValueForKey: @"report"];
    >
    > return tmpValue;
    > }
    >
    >
    > - (NSString *)constructFarmReport
    > {
    > NSString *reportString = [[NSString alloc] initWithString:@""];
    > NSString *farm = [self primitiveValueForKey:@"farmName"];
    > NSString *manager = [self primitiveValueForKey:@"managerName"];
    > ...
    >
    > When the report method is called due to a change in farmName/
    > managerName, it will call constructFarmReport which builds the
    > report string and returns it.  Note that I am using the method
    > primitiveValueForKey to access the values farmName/managerName
    > instead of accessing the identifiers directly.  I've found that in
    > the debugger, if I don't use primitiveValueForKey, then the
    > willAccessValueForKey/didAccessValueForKey methods get invoked.  My
    > question is: is using the primitive method to obtain the values of
    > these attributes a bad thing?  I know the Core Data document
    > discourages one from using the primitive version of the call, and
    > encourages use of either valueForKey: or access the identifier
    > directly, but if control is already in a method which was invoked
    > BECAUSE of KVO, is accessing that variable again INSIDE of the
    > observed method a bad thing?

    Why would it be called JUST because of KVO? If you use the report
    property anywhere, it could just be called because the report value
    is needed for (inital) display or something. Generally, when you
    access a variable in CD you should use valueForKey or call
    willAccessValueForKey/didAccessForKey, I don't see any reason why
    this situation is any different. I can imagine that CD has to fetch
    or update the value for farmName or managerName (I don't really know
    how willAccessValueForKey/didAccessForKey are used, but they can do
    something).

    Christiaan

    > --
    > Boisy G. Pitre
    > 337.781.3570 mobile
    > email: <boisy...>
    > Website: www.boisypitre.com
    >
    > "If there is truth to the proposition that knowing the past helps
    > us to understand the present, I believe there is at least as much
    > truth to the proposition that what we know of the present is
    > crucial to our understanding of the past.  What we have not
    > ourselves experienced or observed we can at most only partially and
    > imperfectly comprehend; and I suspect that there is much in history
    > that is so remote from our own experiences or observations as to be
    > largely beyond our understanding." - Kenneth M. Stamp
    >
    >
    >
    > _______________________________________________
    > MacOSX-dev mailing list
    > <MacOSX-dev...>
    > http://www.omnigroup.com/mailman/listinfo/macosx-dev
  • On Jan 31, 2007, at 9:32 AM, Boisy Pitre wrote:

    > My question is: is using the primitive method to obtain the values
    > of these attributes a bad thing?  I know the Core Data document
    > discourages one from using the primitive version of the call, and
    > encourages use of either valueForKey: or access the identifier
    > directly, but if control is already in a method which was invoked
    > BECAUSE of KVO, is accessing that variable again INSIDE of the
    > observed method a bad thing?
    >
    Yes -- it's not clear why you would ignore the advice in the
    documentation?  The will/didAccess.. calls are required to fire faults.

    mmalc
  • I think the OP meant the remark about KVO the other way around: he
    seems to think that the report is called only because KVO told that
    the underlying data has changed. At least that is what I understood,
    and remarked this assumption is generally incorrect.

    Generally, when accessing properties managed by CD, one should use
    the proper non-primitive methods or wrap will/didAccessValueForKey
    methods around the primitive accessors. That's what the docs say, and
    I assume that's for a reason. The reason I can think of is that the
    will/didAccess.. methods make sure to fire the fault (fetch/update
    the value) if necessary. That would make sense to me, knowing that CD
    doesn't fetch properties immediately. Anyway, I don't know what it
    does, and I don't need to know. The only thing I need to know is what
    is in the docs: you better do it make sure the will/didAccess...
    methods are called. HOWEVER, if you choose to use primitive
    accessors, you are responsible to make sure everything is set up
    right. When you also don't use the will/didAccess... methods, you
    have to make sure that everything these methods does (like
    faulting,etc ?) has been taken care of. This DOES mean you need to
    know what these methods do (and you don't, unless you work for Apple,
    but also that is not true, as some framework developer might need to
    subclass these methods).

    So to conclude. Can it hurt? The answer is: Yes.

    Christiaan

    On 3 Feb 2007, at 8:47 PM, Marcus S. Zarra wrote:

    > It is true that -valueForKey: does not cause the KVO to fire and
    > that the OP could just use that instead of the primitive
    > accessors.  But it also does not hurt anything, especially if he
    > has some other logic sitting in the -(NSString*)reportName; method
    > that he does not want to fire.
    >
    > Marcus S. Zarra
    > Zarra Studios LLC
    > Simply Elegant Software for OS X
    > www.zarrastudios.com
    >
    > On Feb 2, 2007, at 4:07 PM, Christiaan Hofman wrote:
    >
    >>
    >> On 31 Jan 2007, at 6:32 PM, Boisy Pitre wrote:
    >>
    >>> For the last couple of weeks I have been navigating through the
    >>> Core Data swamp and have made significant progress in my
    >>> understanding of the architecture.  That said, there are a couple
    >>> of things that really have me shaking my head, and I would
    >>> appreciate a second look.
    >>>
    >>> Real quick: my application is intended to track information about
    >>> animals on different farms.  The data model has three entities:
    >>>
    >>> - FARM <-->> ANIMAL <-->> VACCINATION
    >>>
    >>> Note the relationships between each entity are to-many going in
    >>> the right direction and to-one going in the left (inverse)
    >>> direction.  A farm can contain many animals and each animal can
    >>> have multiple vaccinations.
    >>>
    >>> Without getting into too much detail, the FARM entity has a
    >>> transient property report(a string) which depends on other
    >>> attributes in the FARM entity changes.  So the initialize method
    >>> in my FARM Managed Object class is:
    >>>
    >>> + (void)initialize
    >>> {
    >>> [self setKeys:[NSArray arrayWithObjects:
    >>> @"farmName",
    >>> @"managerName",
    >>> nil]
    >>> triggerChangeNotificationsForDependentKey:@"report"];
    >>> }
    >>>
    >>> The attributes farmName and managerName are updated in text
    >>> fields in a window and are updated daily.  The idea is that when
    >>> either of these values change, the report attribute should be
    >>> updated to reflect changes to the names.  My report method:
    >>>
    >>> - (NSString *)report
    >>> {
    >>> NSString * tmpValue = nil;
    >>>
    >>> [self willAccessValueForKey: @"report"];
    >>> tmpValue = [self constructFarmReport];
    >>> [self didAccessValueForKey: @"report"];
    >>>
    >>> return tmpValue;
    >>> }
    >>>
    >>>
    >>> - (NSString *)constructFarmReport
    >>> {
    >>> NSString *reportString = [[NSString alloc] initWithString:@""];
    >>> NSString *farm = [self primitiveValueForKey:@"farmName"];
    >>> NSString *manager = [self primitiveValueForKey:@"managerName"];
    >>> ...
    >>>
    >>> When the report method is called due to a change in farmName/
    >>> managerName, it will call constructFarmReport which builds the
    >>> report string and returns it.  Note that I am using the method
    >>> primitiveValueForKey to access the values farmName/managerName
    >>> instead of accessing the identifiers directly.  I've found that
    >>> in the debugger, if I don't use primitiveValueForKey, then the
    >>> willAccessValueForKey/didAccessValueForKey methods get invoked.
    >>> My question is: is using the primitive method to obtain the
    >>> values of these attributes a bad thing?  I know the Core Data
    >>> document discourages one from using the primitive version of the
    >>> call, and encourages use of either valueForKey: or access the
    >>> identifier directly, but if control is already in a method which
    >>> was invoked BECAUSE of KVO, is accessing that variable again
    >>> INSIDE of the observed method a bad thing?
    >>
    >>
    >> Why would it be called JUST because of KVO? If you use the report
    >> property anywhere, it could just be called because the report
    >> value is needed for (inital) display or something. Generally, when
    >> you access a variable in CD you should use valueForKey or call
    >> willAccessValueForKey/didAccessForKey, I don't see any reason why
    >> this situation is any different. I can imagine that CD has to
    >> fetch or update the value for farmName or managerName (I don't
    >> really know how willAccessValueForKey/didAccessForKey are used,
    >> but they can do something).
    >>
    >> Christiaan
    >>
    >>> --
    >>> Boisy G. Pitre
    >>> 337.781.3570 mobile
    >>> email: <boisy...>
    >>> Website: www.boisypitre.com
    >>>
    >>> "If there is truth to the proposition that knowing the past helps
    >>> us to understand the present, I believe there is at least as much
    >>> truth to the proposition that what we know of the present is
    >>> crucial to our understanding of the past.  What we have not
    >>> ourselves experienced or observed we can at most only partially
    >>> and imperfectly comprehend; and I suspect that there is much in
    >>> history that is so remote from our own experiences or
    >>> observations as to be largely beyond our understanding." -
    >>> Kenneth M. Stamp
  • The KVO methods do not fire faults in Core Data.  Core Data retrieves
    all of the values for a managed object when that object is accessed.
    It specifically does not do any lazy initialization of attributes.
    However, it does do lazy initialization of relationships.

    The primitive methods will cause a fault to fire on a lazy
    relationship.  If you access another managed object via -
    primitiveValueForKey: and that object has not been loaded yet -- the -
    primitiveValueForKey: method will cause it to fire.  This can be
    tested very easily.

    The -willChangeValueForKey: and -didChangeValueForKey: should be
    wrapped around any calls to primitive setters -- not getters.  The
    will/did methods cause a KVO notice to be sent out to let other
    observers know that the value has changed.  It does not make sense to
    fire the will/did when you are reading the value.  In the example the
    OP posted, the will/did are not necessary and accessing the values in
    the same managed object via the primitive methods is safe and makes
    sense in some situations.

    Marcus S. Zarra
    Zarra Studios LLC
    Simply Elegant Software for OS X
    www.zarrastudios.com

    On Feb 5, 2007, at 6:40 AM, Christiaan Hofman wrote:

    > I think the OP meant the remark about KVO the other way around: he
    > seems to think that the report is called only because KVO told that
    > the underlying data has changed. At least that is what I
    > understood, and remarked this assumption is generally incorrect.
    >
    > Generally, when accessing properties managed by CD, one should use
    > the proper non-primitive methods or wrap will/didAccessValueForKey
    > methods around the primitive accessors. That's what the docs say,
    > and I assume that's for a reason. The reason I can think of is that
    > the will/didAccess.. methods make sure to fire the fault (fetch/
    > update the value) if necessary. That would make sense to me,
    > knowing that CD doesn't fetch properties immediately. Anyway, I
    > don't know what it does, and I don't need to know. The only thing I
    > need to know is what is in the docs: you better do it make sure the
    > will/didAccess... methods are called. HOWEVER, if you choose to use
    > primitive accessors, you are responsible to make sure everything is
    > set up right. When you also don't use the will/didAccess...
    > methods, you have to make sure that everything these methods does
    > (like faulting,etc ?) has been taken care of. This DOES mean you
    > need to know what these methods do (and you don't, unless you work
    > for Apple, but also that is not true, as some framework developer
    > might need to subclass these methods).
    >
    > So to conclude. Can it hurt? The answer is: Yes.
    >
    > Christiaan
  • On 2/5/07, Marcus S. Zarra <mzarra...> wrote:
    > The KVO methods do not fire faults in Core Data.  Core Data retrieves
    > all of the values for a managed object when that object is accessed.
    > It specifically does not do any lazy initialization of attributes.
    > However, it does do lazy initialization of relationships.
    >
    > The primitive methods will cause a fault to fire on a lazy
    > relationship.  If you access another managed object via -
    > primitiveValueForKey: and that object has not been loaded yet -- the -
    > primitiveValueForKey: method will cause it to fire.  This can be
    > tested very easily.
    >
    > The -willChangeValueForKey: and -didChangeValueForKey: should be
    > wrapped around any calls to primitive setters -- not getters.

    ...and folks are talking about will/didAccessValueForKey: [1].

    For example...

    - (Measure *)measure {
        id tmpObject;
        [self willAccessValueForKey: @"measure"];
        tmpObject = [self primitiveValueForKey: @"measure"];
        [self didAccessValueForKey: @"measure"];
        return tmpObject;
    }

    - (void)setMeasure:(Measure *)value {
        [self willChangeValueForKey: @"measure"];
        [self setPrimitiveValue: value forKey: @"measure"];
        [self didChangeValueForKey: @"measure"];
    }

    [1] <http://developer.apple.com/documentation/Cocoa/Reference/CoreDataFramework/
    Classes/NSManagedObject_Class/Reference/Reference.html#//apple_ref/occ/inst
    m/NSManagedObject/didAccessValueForKey:
    >
  • On 2/5/07, Marcus S. Zarra <mzarra...> wrote:
    > The KVO methods do not fire faults in Core Data.  Core Data retrieves
    > all of the values for a managed object when that object is accessed.
    > It specifically does not do any lazy initialization of attributes.
    > However, it does do lazy initialization of relationships.

    I should also note that your are making assumption about how Core Data
    will operate... it could change its faulting behavior in the future
    (it could lazily load some subset of attributes). Using the correct
    will/did Access/Change methods when dealing with primitive values will
    protect you from changes in the implementation.

    The API and documentation do not preclude that Apple could extend Core
    Data in such ways... (in fact the documentation recommendations and
    API actually support that type of enhancement)

    -Shawn
  • On 5 Feb 2007, at 6:19 PM, Shawn Erickson wrote:

    > On 2/5/07, Marcus S. Zarra <mzarra...> wrote:
    >> The KVO methods do not fire faults in Core Data.

    So why does the documentation on didAccessValueForKey : say /
    explicitly/:

    Together with willAccessValueForKey:, this method is used to fire
    faults, ...

    (see the link in the earlier mail from Shawn Erickson).

    >> Core Data retrieves
    >> all of the values for a managed object when that object is accessed.
    >> It specifically does not do any lazy initialization of attributes.
    >> However, it does do lazy initialization of relationships.
    >
    > I should also note that your are making assumption about how Core Data
    > will operate... it could change its faulting behavior in the future
    > (it could lazily load some subset of attributes). Using the correct
    > will/did Access/Change methods when dealing with primitive values will
    > protect you from changes in the implementation.
    >
    > The API and documentation do not preclude that Apple could extend Core
    > Data in such ways... (in fact the documentation recommendations and
    > API actually support that type of enhancement)
    >
    > -Shawn

    Exactly my point: perhaps it does nothing in some specific cases, but
    you cannot rely on that as long the documentation says otherwise. And
    as I noted: subclassers could also change that behavior.

    Christiaan
  • On Feb 5, 2007, at 9:04 AM, Marcus S. Zarra wrote:

    > The KVO methods do not fire faults in Core Data. [...]
    > The primitive methods will cause a fault to fire on a lazy
    > relationship.

    Even if that's true now (and I don't think it is), it could change in
    the future. It's an implementation detail which is encapsulated and
    shouldn't be relied on.

    > The -willChangeValueForKey: and -didChangeValueForKey: should be
    > wrapped around any calls to primitive setters -- not getters

    True, but these are easily confused with -will__Access__ValueForKey:
    and -did__Access__ValueForKey: which do (potentially) fire faults.

    There are two sets of will/did notifications:

    Getters:
    - willAccessValueForKey;
    - didAccessValueForKey;

    Setters:
    - willChangeValueForKey:
    - didChangeValueForKey:

    I heard your Late Night Cocoa interview* (which was quite good), so
    you clearly know what you're talking about. I suspect there was a
    typo somewhere in this thread that caused all of this confusion.

    Ironically, the word confusion is right in the thread name.

        - Scott

    (* http://latenightcocoa.com/?q=node/16)