Core Data: Custom to-many relationship setter not being invoked

  • Hi folks,

    I'm clearly doing something daft but unable to see the error of my ways.

    Distilling my problem down into the Department & Employees example, both are custom NSManagedObject subclasses, each with an inverse to-many / to-one relationship as you'd expect. My problem is that Department's custom -awakeFromInsert gets called, yet its -addEmployeesObject and -addEmployees methods don't ever get called. If I add employees in the app, it all works swimmingly, but my custom accessors aren't ever used.

    As per searches on why custom Core Data accessors aren't being called, I've checked the model specifies that the Department entity specifies the custom class (which it does, no matter how many times I keep checking it). And it must be, else the custom -awakeFromInsert wouldn't be firing. Ditto the Employee entity specifies the Employee class.

    The custom accessors are as per Xcode's Design -> Data Model -> Copy Obj-C 2.0 Method Invocations / Declarations to Clipboard, I'm doing nothing clever with them (in this sample app). It makes no difference if I use the Obj-C 1.0 templates from the same menu either.

    Can't figure out why the initialiser is being called, but not the custom setters.

    On the other hand the Employee class can have a custom -setDepartment like so:

    - (void)setDepartment:(Department *)value
    {
    [self willChangeValueForKey:@"department"];
    [self setValue:value forKey:@"primitiveDepartment"];
    [self didChangeValueForKey:@"department"];
    }

    ... which does get called. Sob...

    I wouldn't mind so much if the app didn't actually work correctly, but that it's deliberately ignoring my lovely custom accessors is a slap in the face...

    Thanks in advance for any "you stupid idiot you need to do this, man" replies :)

    Cheers,
    Ken

    . . . . . . . . . . . . . . . . . . . . . . . . . . .
    Dr. Ken Tabb
    Mac & UNIX programmer
    Neural network & computer vision researcher
    University of Hertfordshire, UK
  • On 2010 Feb 22, at 14:59, Ken Tabb wrote:

    > My problem is that Department's custom -awakeFromInsert gets called, yet its -addEmployeesObject and -addEmployees methods don't ever get called. If I add employees in the app

    I believe that Core Data does a wholesale replacement.  Try overriding -setEmployees: and see if that works.  Just as if it were a regular attribute.  Something like this method I use:

    - (void)setTriggers:(NSSet*)value {
        [self postWillSetNewTriggers:value] ;

        [self willChangeValueForKey:constKeyTriggers];
        [self setPrimitiveTriggers:[NSMutableSet setWithSet:value]];
        [self didChangeValueForKey:constKeyTriggers];
    }

    If this works, do not delete your other custom setters, because you don't know how Core Data may decide to mutate the set in Mac OS 10.7.  It's an "implementation detail".

    Also, consider observing the value using KVO, instead of custom setters.
  • On Feb 22, 2010, at 3:59 PM, Ken Tabb wrote:

    > Hi folks,
    >
    > I'm clearly doing something daft but unable to see the error of my ways.
    >
    > Distilling my problem down into the Department & Employees example, both are custom NSManagedObject subclasses, each with an inverse to-many / to-one relationship as you'd expect. My problem is that Department's custom -awakeFromInsert gets called, yet its -addEmployeesObject and -addEmployees methods don't ever get called. If I add employees in the app, it all works swimmingly, but my custom accessors aren't ever used.

    Do you implement both the add<key> *and* remove<key>? The framework might require both to assume compliance.

    HTH,

    Keary Suska
    Esoteritech, Inc.
    "Demystifying technology for your home or business"
  • Hi Jerry,

    thanks for the reply. You're right, implementing -setEmployees works
    like a charm. There's no mention of it in the CoreData.pdf though,
    that I can find.

    I will try to use KVO observations, but my purpose is actually to
    maintain a linked list of employees (OK the Department / Employee
    analogy is breaking down here!).

    Thanks again for the info, I'll meanwhile file a bug about the 10.6
    documentation.

    Cheers,
    Ken

    On 22 Feb 2010, at 11:21, Jerry Krinock wrote:

    >
    > On 2010 Feb 22, at 14:59, Ken Tabb wrote:
    >
    >> My problem is that Department's custom -awakeFromInsert gets
    >> called, yet its -addEmployeesObject and -addEmployees methods don't
    >> ever get called. If I add employees in the app
    >
    > I believe that Core Data does a wholesale replacement.  Try
    > overriding -setEmployees: and see if that works.  Just as if it were
    > a regular attribute.  Something like this method I use:
    >
    > - (void)setTriggers:(NSSet*)value {
    > [self postWillSetNewTriggers:value] ;
    >
    > [self willChangeValueForKey:constKeyTriggers];
    > [self setPrimitiveTriggers:[NSMutableSet setWithSet:value]];
    > [self didChangeValueForKey:constKeyTriggers];
    > }
    >
    > If this works, do not delete your other custom setters, because you
    > don't know how Core Data may decide to mutate the set in Mac OS
    > 10.7.  It's an "implementation detail".
    >
    > Also, consider observing the value using KVO, instead of custom
    > setters.

    - - - - - - - - - -
    Dr. Ken Tabb
    Mac & UNIX Developer - Health & Human Sciences
    Machine Vision & Neural Network researcher - School of Computer Science
    University of Hertfordshire, UK
  • Hi Keary,

    thanks for your reply. Yep I implemented all 4, as per the Design ->
    Data Model -> Copy to clipboard template, i.e.

    - (void)addEmployeesObject:(Employee *)value;
    - (void)removeEmployeesObject:(Employee *)value;
    - (void)addEmployees:(NSSet *)value;
    - (void)removeEmployees:(NSSet *)value;

    However if I implement -setEmployees as per Jerry's e-mail (and
    seemingly contravening the advice in the Core Data Programming Guide),
    then it works like a charm :-/

    Thanks for taking the time to help,
    Ken

    On 22 Feb 2010, at 11:21, Keary Suska wrote:

    > On Feb 22, 2010, at 3:59 PM, Ken Tabb wrote:
    >
    >> Hi folks,
    >>
    >> I'm clearly doing something daft but unable to see the error of my
    >> ways.
    >>
    >> Distilling my problem down into the Department & Employees example,
    >> both are custom NSManagedObject subclasses, each with an inverse to-
    >> many / to-one relationship as you'd expect. My problem is that
    >> Department's custom -awakeFromInsert gets called, yet its -
    >> addEmployeesObject and -addEmployees methods don't ever get called.
    >> If I add employees in the app, it all works swimmingly, but my
    >> custom accessors aren't ever used.
    >
    > Do you implement both the add<key> *and* remove<key>? The framework
    > might require both to assume compliance.
    >
    > HTH,
    >
    > Keary Suska
    > Esoteritech, Inc.
    > "Demystifying technology for your home or business"
    >

    - - - - - - - - - -
    Dr. Ken Tabb
    Mac & UNIX Developer - Health & Human Sciences
    Machine Vision & Neural Network researcher - School of Computer Science
    University of Hertfordshire, UK
  • On 2010 Feb 22, at 15:53, Ken Tabb wrote:

    > I will try to use KVO observations, but my purpose is actually to maintain a linked list...

    If I recall correctly, the reason why I use custom setters instead of KVO sometimes is because I need a notification *before* the change actually occurs.

    > I'll meanwhile file a bug about the 10.6 documentation.

    Great!  Maybe they'll come back and say that we're doing it All Wrong, but now that you've mentioned it I remember scratching my head over this when I discovered it.  Probably you're a more diligent reader than I am.
  • On Feb 22, 2010, at 15:54, Ken Tabb wrote:

    > Yep I implemented all 4, as per the Design -> Data Model -> Copy to clipboard template, i.e.
    >
    > - (void)addEmployeesObject:(Employee *)value;
    > - (void)removeEmployeesObject:(Employee *)value;
    > - (void)addEmployees:(NSSet *)value;
    > - (void)removeEmployees:(NSSet *)value;
    >
    > However if I implement -setEmployees as per Jerry's e-mail (and seemingly contravening the advice in the Core Data Programming Guide), then it works like a charm :-/

    There's something else going here, though it isn't clear what. One thing you haven't said is *how* you're adding employees. Could you show the code that does this?
  • Adding is via a button going to an Employee array controller's -add.
    In the interface there are 2 array controllers (1 for Departments, 1
    for Employees). The Employees controller is set to use the selection
    in the Departments controller (i.e. showing the subset belonging to
    the selected dept).

    Adding and deleting Departments and Employees is fine (everything gets
    hooked up / added / deleted properly), and if I look in the XML Core
    Data store, all is well. It's just my custom accessors (the 4
    mentioned below) don't get used, whereas -setEmployees does.

    Do you reckon it's because the adding is happening from the Employee
    side of things rather than the Department side of things? Shouldn't
    both sides have their accessor methods called (thanks to the inverse
    relationship)?

    I can't believe it's relevant, but the Department's 'employees'
    relationship is mandatory, as is the inverse relationship.

    Weird isn't it :)

    Ken

    On 23 Feb 2010, at 2:34, Quincey Morris wrote:

    > On Feb 22, 2010, at 15:54, Ken Tabb wrote:
    >
    >> Yep I implemented all 4, as per the Design -> Data Model -> Copy to
    >> clipboard template, i.e.
    >>
    >> - (void)addEmployeesObject:(Employee *)value;
    >> - (void)removeEmployeesObject:(Employee *)value;
    >> - (void)addEmployees:(NSSet *)value;
    >> - (void)removeEmployees:(NSSet *)value;
    >>
    >> However if I implement -setEmployees as per Jerry's e-mail (and
    >> seemingly contravening the advice in the Core Data Programming
    >> Guide), then it works like a charm :-/
    >
    > There's something else going here, though it isn't clear what. One
    > thing you haven't said is *how* you're adding employees. Could you
    > show the code that does this?

    - - - - - - - - - -
    Dr. Ken Tabb
    Mac & UNIX Developer - Health & Human Sciences
    Machine Vision & Neural Network researcher - School of Computer Science
    University of Hertfordshire, UK
  • > On Tue, 2010/02/23, Ken Tabb <K.J.Tabb...> wrote:
    > From: Ken Tabb <K.J.Tabb...>
    > Subject: Re: Core Data: Custom to-many relationship setter not being invoked
    > To: "Quincey Morris" <quinceymorris...>
    > Cc: "cocoa-dev" <cocoa-dev...>
    > Date: Tuesday, 2010 February 23, 03:20 AM
    > Adding is via a button going to an
    > Employee array controller's -add. In the interface there are
    > 2 array controllers (1 for Departments, 1 for Employees).
    > The Employees controller is set to use the selection in the
    > Departments controller (i.e. showing the subset belonging to
    > the selected dept).
    >
    > Adding and deleting Departments and Employees is fine
    > (everything gets hooked up / added / deleted properly), and
    > if I look in the XML Core Data store, all is well. It's just
    > my custom accessors (the 4 mentioned below) don't get used,
    > whereas -setEmployees does.
    >
    > Do you reckon it's because the adding is happening from the
    > Employee side of things rather than the Department side of
    > things? Shouldn't both sides have their accessor methods
    > called (thanks to the inverse relationship)?
    >
    > I can't believe it's relevant, but the Department's
    > 'employees' relationship is mandatory, as is the inverse
    > relationship.
    >
    > Weird isn't it :)
    >
    > Ken
    >
    > On 23 Feb 2010, at 2:34, Quincey Morris wrote:
    >
    >> On Feb 22, 2010, at 15:54, Ken Tabb wrote:
    >>
    >>> Yep I implemented all 4, as per the Design ->
    > Data Model -> Copy to clipboard template, i.e.
    >>>
    >>> - (void)addEmployeesObject:(Employee *)value;
    >>> - (void)removeEmployeesObject:(Employee *)value;
    >>> - (void)addEmployees:(NSSet *)value;
    >>> - (void)removeEmployees:(NSSet *)value;
    >>>
    >>> However if I implement -setEmployees as per
    > Jerry's e-mail (and seemingly contravening the advice in the
    > Core Data Programming Guide), then it works like a charm
    > :-/
    >>
    >> There's something else going here, though it isn't
    > clear what. One thing you haven't said is *how* you're
    > adding employees. Could you show the code that does this?

    It's not something simple like
    Employees vs. Employee
    is it?
  • Hi Jeffrey,

    well in the model, the Department's relationship is defined as
    'employees', and when I copy to clipboard from the model (as per
    Xcode's Design -> Data Model -> copy to clipboard), everything in the
    boilerplate code is "employees" (plural). If I edit them to -
    addEmployeeObject / -addEmployee (singular), they also don't get called.

    Fire the lot of them I say, they're causing me too much aggro ;)

    Ken

    On 23 Feb 2010, at 4:05, Jeffrey Oleander wrote:

    > It's not something simple like
    > Employees vs. Employee
    > is it?

    - - - - - - - - - -
    Dr. Ken Tabb
    Mac & UNIX Developer - Health & Human Sciences
    Machine Vision & Neural Network researcher - School of Computer Science
    University of Hertfordshire, UK
  • On Feb 23, 2010, at 01:20, Ken Tabb wrote:

    > Adding is via a button going to an Employee array controller's -add. In the interface there are 2 array controllers (1 for Departments, 1 for Employees). The Employees controller is set to use the selection in the Departments controller (i.e. showing the subset belonging to the selected dept).

    You haven't actually told us the whole story. Calling the Employee array controller's 'add:' method causes a new Employee object to be created with default attributes and no relationships -- no Department. That means the code to assign it to a Department is elsewhere.

    > Adding and deleting Departments and Employees is fine (everything gets hooked up / added / deleted properly), and if I look in the XML Core Data store, all is well. It's just my custom accessors (the 4 mentioned below) don't get used, whereas -setEmployees does.

    If you did not try this already, set a breakpoint inside 'setEmployees:'. When you hit it, type the debugger command 'po [self class]' in the Xcode console window to find out the actual class of the Department object.

    > Do you reckon it's because the adding is happening from the Employee side of things rather than the Department side of things? Shouldn't both sides have their accessor methods called (thanks to the inverse relationship)?

    There are no "sides" as far as adding objects is concerned. There are "sides" when you talk about establishing relationships, but we don't know how you do this yet. Also, the puzzle here is not whether accessor methods are being called, but which accessor methods are being called. The setter, for a to-many property, is kind of the worst-case fallback accessor, and KVC should prefer the more nuanced add/remove accessors if they are available.

    > I can't believe it's relevant, but the Department's 'employees' relationship is mandatory, as is the inverse relationship.

    No, it's not relevant -- such validation requirements are checked only when the Core Data store is about to be saved.
  • On 23 Feb 2010, at 6:19, Quincey Morris wrote:

    >> Adding is via a button going to an Employee array controller's -add. In the interface there are 2 array controllers (1 for Departments, 1 for Employees). The Employees controller is set to use the selection in the Departments controller (i.e. showing the subset belonging to the selected dept).
    >
    > You haven't actually told us the whole story. Calling the Employee array controller's 'add:' method causes a new Employee object to be created with default attributes and no relationships -- no Department. That means the code to assign it to a Department is elsewhere.

    Sorry perhaps I didn't make myself clear. The button calls -add on an Employee array controller (standard NSArrayController), whose content set is bound to controller key "selection" and model key path "employees" of another standard array controller, containing Departments. So when the button tells the Employee controller to add a new employee, it adds it to the selected Department. i.e. standard Core Data demo stuff. So a new employee is automatically belonging to a department (the selected one in the GUI when the button was hit).

    The Employee -awakeFromInsert isn't doing anything wacky, and doesn't touch the "department" attribute (it just calls super and then sets a data attribute to "today"). There is no -awakeFromFetch in Employee as nothing custom needs to be done upon fetching an Employee object.

    Neither the Department nor Employee classes actually do any setting of attributes (i.e. nothing in my code is setting the specific Department for an Employee, nor which Employees belong to a Department). All that is being done by standard IB / Bindings methods (which I'm not overriding / subclassing). And as I say, if I look in the XML store after I have quit, all is well and properly hooked up (on each side).

    If there's anything I'm missing out telling you here, by all means shout but I can't think of anything I'm withholding.

    >> Adding and deleting Departments and Employees is fine (everything gets hooked up / added / deleted properly), and if I look in the XML Core Data store, all is well. It's just my custom accessors (the 4 mentioned below) don't get used, whereas -setEmployees does.
    >
    > If you did not try this already, set a breakpoint inside 'setEmployees:'. When you hit it, type the debugger command 'po [self class]' in the Xcode console window to find out the actual class of the Department object.

    It tells me it's a Department object :)

    >> Do you reckon it's because the adding is happening from the Employee side of things rather than the Department side of things? Shouldn't both sides have their accessor methods called (thanks to the inverse relationship)?
    >
    > There are no "sides" as far as adding objects is concerned. There are "sides" when you talk about establishing relationships, but we don't know how you do this yet. Also, the puzzle here is not whether accessor methods are being called, but which accessor methods are being called. The setter, for a to-many property, is kind of the worst-case fallback accessor, and KVC should prefer the more nuanced add/remove accessors if they are available.
    >
    >> I can't believe it's relevant, but the Department's 'employees' relationship is mandatory, as is the inverse relationship.
    >
    > No, it's not relevant -- such validation requirements are checked only when the Core Data store is about to be saved.

    These last 2 theories were what I presumed, but you know how desperate the theories start to become after a while :)

    Thanks again for your help and time,
    Ken

    . . . . . . . . . . . . . . . . . . . . . . . . . . .
    Dr. Ken Tabb
    Mac & UNIX programmer
    Neural network & computer vision researcher
    University of Hertfordshire, UK
  • On Feb 23, 2010, at 11:08, Ken Tabb wrote:

    > These last 2 theories were what I presumed, but you know how desperate the theories start to become after a while :)

    Yeah, I know how that goes.

    It sounds like it's bug reporter time. You're leveraging a "free" method of getting your relationships set up (using array controller behavior), but it's not happening in the expected way (using your custom accessors). Either there's something wrong with the behavior, or we're looking for the problem in the wrong place.

    If you care to investigate further, though, there are still a couple of things you could try, to see if they are revealing in any way.

    Add a method of (say) transferring an employee to a different department. Implement it in the following alternate ways, in turn:

    1. By using the Employee's setDepartment method.

    2. By calling your Department's custom add/remove Employee methods directly (to verify that they actually work, though this is not at issue so far).

    3. By using standard KVO compliant techniques. Call the standard NSSet add/remove object methods on a mutable set proxy ([department mutableSetValueForKey: @"employees"]).

    All three techniques should produce the same results, and should all end up at your Department custom accessor methods rather than at 'setEmployees:'.
  • On Feb 22, 2010, at 2:59 pm, Ken Tabb wrote:

    > Distilling my problem down into the Department & Employees example, both are custom NSManagedObject subclasses, each with an inverse to-many / to-one relationship as you'd expect. My problem is that Department's custom -awakeFromInsert gets called, yet its -addEmployeesObject and -addEmployees methods don't ever get called. If I add employees in the app, it all works swimmingly, but my custom accessors aren't ever used.
    >
    <http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreD
    ata/Articles/cdTroubleshooting.html#//apple_ref/doc/uid/TP40002320-SW3
    >

    Custom relationship set mutator methods are not invoked by an array controller
    Problem: You have implemented set mutator methods for a relationship as described in “Custom To-Many Relationship Accessor Methods,” and have bound thecontentSet binding of an NSArrayController instance to a relationship (as illustrated by the Employees array controller in NSPersistentDocument Core Data Tutorial), but the set mutator methods are not invoked when you add objects to and remove objects from the array controller.

    Cause: This is a bug.

    Remedy: You can work around this by adding self to the contentSet binding's key path. For example, instead of binding to [Department Object Controller].selection.employees, you would bind to [Department Object Controller].selection.self.employees.

    mmalc
  • On 23 Feb 2010, at 9:17, mmalc Crawford wrote:

    > Data/Articles/cdTroubleshooting.html#//apple_ref/doc/uid/TP40002320-SW3>
    >
    > Custom relationship set mutator methods are not invoked by an array controller
    > Problem: You have implemented set mutator methods for a relationship as described
    > in "Custom To-Many Relationship Accessor Methods", and have bound
    > the contentSet binding of an NSArrayController instance to a relationship
    > (as illustrated by the Employees array controller in NSPersistentDocument
    > Core Data Tutorial), but the set mutator methods are not invoked when you add
    > objects to and remove objects from the array controller.
    >
    > Cause: This is a bug.
    >
    > Remedy: You can work around this by adding self to the contentSet binding's
    > key path. For example, instead of binding to [Department Object Controller
    > ].selection.employees, you would bind to [Department Object Controller].sel=
    > ection.self.employees.
    >
    > mmalc

    Sob.

    I only wish that, when I'd read this very section several times, I hadn't thought "no that's not the problem I'm seeing, reckon I've got a live one" :-/

    I've just put an update on bug 7677425, so that they know to mark it as a duplicate etc.

    As it happens, it turns out I didn't need custom accessors anyway and can do everything I need via KVO, but I couldn't see what I was doing wrong, so presumed I was misunderstanding it (a common cause, you'll be surprised to hear).

    Thanks folks,
    Ken
    Tail between his legs again...

    . . . . . . . . . . . . . . . . . . . . . . . . . . .
    Dr. Ken Tabb
    Mac & UNIX programmer
    Neural network & computer vision researcher
    University of Hertfordshire, UK
  • On 2010 Feb 23, at 13:17, mmalc Crawford wrote:

    > <http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreD
    ata/Articles/cdTroubleshooting.html#//apple_ref/doc/uid/TP40002320-SW3
    >
    >
    > Custom relationship set mutator methods are not invoked by an array controller
    > Problem: You have implemented set mutator methods for a relationship as described in “Custom To-Many Relationship Accessor Methods,” and have bound thecontentSet binding of an NSArrayController instance to a relationship (as illustrated by the Employees array controller in NSPersistentDocument Core Data Tutorial), but the set mutator methods are not invoked when you add objects to and remove objects from the array controller.
    >
    > Cause: This is a bug.
    >
    > Remedy: You can work around this by adding self to the contentSet binding's key path. For example, instead of binding to [Department Object Controller].selection.employees, you would bind to [Department Object Controller].selection.self.employees.

    Thanks for the pointer to the docs, mmalc.  You are concise and accurate as usual.  But I like my workaround (implementing setEmployees:)  better, because I can put a comment in the code.  If I entered a Model Key Path of "selection.self.employees", I'd be worried that someone might look at it one of these days and say "Hmmm.  Stupid Jerry.  We don't need that '.self' in there, do we!"

    Furthermore, I've never been able to find any documentation stating that Cocoa is required to invoke the set mutator method(s).  Invoking the setEmployees: method, which both Ken and I have noted *does* happen, is a KVC-compliant technique.  So, I'm not sure that it's a bug.

    Finally, there are other cases when you're not sure which method is going to be invoked.  For example, say that multiple employees are added.  Does it invoke addEmployees:, or does it invoke addEmployeesObject: multiple times?

    So, I'm sticking to my plan that it is to use KVO whenever possible.  But if you need notification *before* the change occurs, you need to override all *five* setters:

    - (void)addEmployeesObject:(Employee *)value;
    - (void)removeEmployeesObject:(Employee *)value;
    - (void)addEmployees:(NSSet *)value;
    - (void)removeEmployees:(NSSet *)value;
    - (void)setEmployees:(NSSet *)set;

    Now I may be overly presumptive in declaring that there are *five* set mutator methods; the four set mutators you get from "Copy Obj-C 2.0 Method Implementations to Clipboard", and the one that we've discovered is actually being used.  The documentation:

    http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreD
    ata/Articles/cdAccessorMethods.html#//apple_ref/doc/uid/TP40002154
      > Custom To-Many Relationship Accessor Methods

    refers rather loosely to "mutator methods (such as...)" but never gives a concise list, although it implies that they are whatever you get in Xcode.  That's not exactly what I'd call an "API Contract".  I have looked for but have never found an unequivocal statement that "Core Data DEFINES 'N' set mutator methods.  They ARE: •, •, •, …."

    Rather than fixing the "bug", I think it would be better if Apple would simply document the current behavior, i.e. "When an array controller makes a change, unless it is bound with the '.self.' workaround, it shall invoke -setEmployees:".  Then, I'd only need to implement one custom setter instead of five.  Well, that is if I trusted myself to not invoke one of the others :)  Also, Core Data apps have been shipping for five years now and changing it at this point might break some of them.
  • On Tue, Feb 23, 2010 at 2:32 PM, Jerry Krinock <jerry...> wrote:
    > Furthermore, I've never been able to find any documentation stating that Cocoa is required to invoke the set mutator method(s).  Invoking the setEmployees: method, which both Ken and I have noted *does* happen, is a KVC-compliant technique.  So, I'm not sure that it's a bug.

    Not quite. KVC compliance refers to implementing the proper methods
    such that -setValue:forKey:, -valueForKey: and
    -mutable(Set|Array)ValueForKey: work. It doesn't refer to how one
    modifies that property. So it doesn't make sense to say that "calling
    -setEmployees: is KVC-compliant." In fact, according to the Accessor
    Search Implementation Details, you don't need to implement -set<Key>:
    at all. It just so happens that Core Data gives you an implementation
    that doesn't do what you need to do, and KVC uses it when convenient.

    The real bug is that NSArrayController doesn't use the fast-path KVC
    methods for updating the target of its contentSet binding, which is
    what exposes the need to override -set<Key>: in this situation.

    --Kyle Sluder
  • On 2010 Feb 23, at 14:52, Kyle Sluder wrote:

    > On Tue, Feb 23, 2010 at 2:32 PM, Jerry Krinock <jerry...> wrote:
    >> Furthermore, I've never been able to find any documentation stating that Cocoa is required to invoke the set mutator method(s).  Invoking the setEmployees: method, which both Ken and I have noted *does* happen, is a KVC-compliant technique.  So, I'm not sure that it's a bug.
    >
    > Not quite. KVC compliance refers to implementing the proper methods
    > such that -setValue:forKey:, -valueForKey: and
    > -mutable(Set|Array)ValueForKey: work. It doesn't refer to how one
    > modifies that property. So it doesn't make sense to say that "calling
    > -setEmployees: is KVC-compliant."

    Well, I said a KVC-compliant technique.  Let's say "making the change in a KVC-compliant way".  But, yes, it's moot...

    > In fact, according to the Accessor
    > Search Implementation Details, you don't need to implement -set<Key>:
    > at all. It just so happens that Core Data gives you an implementation
    > that doesn't do what you need to do, and KVC uses it when convenient.
    > The real bug is that NSArrayController doesn't use the fast-path KVC
    > methods for updating the target of its contentSet binding, which is
    > what exposes the need to override -set<Key>: in this situation.

    OK, I see it now.  It's in the Key-Value Coding Programming Guide > Accessor
    Search Implementation Details > Accessor Search Pattern for Unordered Collections.  The array controller is skipping Step 1 in the search path.  So, I agree it's definitely a bug, either behavior or documentation.
previous month february 2010 next month
MTWTFSS
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
Go to today