Key-Value-Observing and Collections

  • Hi,

    There is something, I just don't get with KVO. Lets say, I have an
    object

    @interface Pupil
    {
    NSMutableArray grades;
    }

    - (void)setGrades:(NSMutableArray *)theGrades;
    - (NSMutableArray *)grades;
    - (void)addGrade:(Grade *)aGrade;

    @end

    Using KVO, I want to be notified not only, when the old grades
    collection object (NSMutableArray) is replaced, but also, when a
    Grade instance is added to the grades array (something like "[grades
    addObject:aGrade]").
    The first case is easy, because I know the attribute name (grades),
    which gives the key. But for the second, I don't know the attribute
    name, so I can't add an observer.
    Can anybody explain me how to do this?

    Thanks
    Phil
  • Hi,

    Call [self willChangeValueForKey:@"grades"] at the beginning of -
    (void)addGrade: and [self didChangeValueForKey:@"grades"] just when
    you changed the grades variable.

    Best,
    Fabian

    Fabian Schuiki
    <fabianschuiki...>

    Am 25.10.2007 um 15:23 schrieb Philip Mötteli:

    > Hi,
    >
    >
    > There is something, I just don't get with KVO. Lets say, I have an
    > object
    >
    >
    > @interface Pupil
    > {
    > NSMutableArray    grades;
    > }
    >
    >
    > - (void)setGrades:(NSMutableArray *)theGrades;
    > - (NSMutableArray *)grades;
    > - (void)addGrade:(Grade *)aGrade;
    >
    > @end
    >
    >
    > Using KVO, I want to be notified not only, when the old grades
    > collection object (NSMutableArray) is replaced, but also, when a
    > Grade instance is added to the grades array (something like
    > "[grades addObject:aGrade]").
    > The first case is easy, because I know the attribute name (grades),
    > which gives the key. But for the second, I don't know the attribute
    > name, so I can't add an observer.
    > Can anybody explain me how to do this?
    >
    >
    > Thanks
    > Phil
    >
    > _______________________________________________
    > MacOSX-dev mailing list
    > <MacOSX-dev...>
    > http://www.omnigroup.com/mailman/listinfo/macosx-dev
  • You should avoid that, in particular for collection keys (for those
    there are other variants that allow you to pass precisely what has
    changed). A much better and easier solution is to follow the docs:
    use KVC compliant array accessors, like
    insertObject:inGradesAtIndex:, which automatically send the correct
    notifications. If you really want to use addGrade:, just make it a
    wrapper around this KVC compliant method.

    Christiaan

    On 25 Oct 2007, at 4:35 PM, Fabian Schuiki wrote:

    > Hi,
    >
    > Call [self willChangeValueForKey:@"grades"] at the beginning of -
    > (void)addGrade: and [self didChangeValueForKey:@"grades"] just when
    > you changed the grades variable.
    >
    > Best,
    > Fabian
    >
    > Fabian Schuiki
    > <fabianschuiki...>
    >
    >
    > Am 25.10.2007 um 15:23 schrieb Philip Mötteli:
    >
    >> Hi,
    >>
    >>
    >> There is something, I just don't get with KVO. Lets say, I have an
    >> object
    >>
    >>
    >> @interface Pupil
    >> {
    >> NSMutableArray    grades;
    >> }
    >>
    >>
    >> - (void)setGrades:(NSMutableArray *)theGrades;
    >> - (NSMutableArray *)grades;
    >> - (void)addGrade:(Grade *)aGrade;
    >>
    >> @end
    >>
    >>
    >> Using KVO, I want to be notified not only, when the old grades
    >> collection object (NSMutableArray) is replaced, but also, when a
    >> Grade instance is added to the grades array (something like
    >> "[grades addObject:aGrade]").
    >> The first case is easy, because I know the attribute name
    >> (grades), which gives the key. But for the second, I don't know
    >> the attribute name, so I can't add an observer.
    >> Can anybody explain me how to do this?
    >>
    >>
    >> Thanks
    >> Phil
    >>
    >> _______________________________________________
    >> MacOSX-dev mailing list
    >> <MacOSX-dev...>
    >> http://www.omnigroup.com/mailman/listinfo/macosx-dev
    >
    > _______________________________________________
    > MacOSX-dev mailing list
    > <MacOSX-dev...>
    > http://www.omnigroup.com/mailman/listinfo/macosx-dev
  • Am 25.10.2007 um 16:47 schrieb Christiaan Hofman:

    > You should avoid that, in particular for collection keys (for those
    > there are other variants that allow you to pass precisely what has
    > changed). A much better and easier solution is to follow the docs:
    > use KVC compliant array accessors, like
    > insertObject:inGradesAtIndex:, which automatically send the correct
    > notifications.

    And how do I register as an observer?
    [theCollection addObserver:anObserver forKeyPath:???? options:0
    context:NULL];

    What do I have to use as the key(path)?

    Thanks
    Phil
  • On Oct 25, 2007, at 8:01 AM, Philip Mötteli wrote:

    > Am 25.10.2007 um 16:47 schrieb Christiaan Hofman:
    >
    >> You should avoid that, in particular for collection keys (for those
    >> there are other variants that allow you to pass precisely what has
    >> changed). A much better and easier solution is to follow the docs:
    >> use KVC compliant array accessors, like
    >> insertObject:inGradesAtIndex:, which automatically send the correct
    >> notifications.
    >
    > And how do I register as an observer?
    >
    > [theCollection addObserver:anObserver forKeyPath:???? options:0
    > context:NULL];
    >
    > What do I have to use as the key(path)?

    You don't.  The point of key-value observing is that you're observing
    a *property* of an object, not an object itself.  In this case, you
    would say

      [objectWithTheCollectionProperty addObserver:anObserver
                                        forKeyPath:@"theCollection"
                                            options:options
                                            context:context];

    and whenever the property *represented by* the key "theCollection" is
    mutated -- via the mutator methods that Christiaan Hoffman mentioned,
    or via a proxy object returned by [objectWithTheCollectionProxy
    mutableArrayValueForKey:@"theCollection"] -- you will receive a KVO
    notification.

    Note too that you probably shouldn't pass NULL for the context.  The
    context helps distinguish whether your -
    observeValueForKeyPath:ofObject:change:context: callback is being
    invoked on behalf of your observance or on behalf of some completely
    unrelated observance.  (This is particularly important when
    implementing views that use KVO to handle bindings.)  Typical practice
    is to declare a C or NSString constant in your code and to pass *that*
    as the context, and then do a pointer-equality check against it
    (rather than an -isEqual: check, since you can't be guaranteed that an
    arbitrary context you're passed is an object).

      -- Chris
previous month october 2007 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
29 30 31        
Go to today