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 collection (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
  • On 10/25/07, Philip Mötteli <Philip.Moetteli...> wrote:
    >
    > - (void)setGrades:(NSMutableArray *)theGrades;
    > - (NSMutableArray *)grades;
    > - (void)addGrade:(Grade *)aGrade;

    You probably want your addGrade method to look like:

    - (void)addGrade:(Grade *)aGrade
    {
            [self willChangeValueForKey:@"grades"];
            [grades addObject:aGrade];
            [self didChangeValueForKey:@"grades"];
    }

    Dave.
  • Philip,

    You can expose 'grades' as a to-many property by adding the following
    methods to Pupil

    - (unsigned int) countOfGrades
    - (id) objectInGradesAtIndex:(unsigned int)index
    - (void) insertObjectInGrades:(id)grade atIndex:(unsigned int)index
    - (void) removeObjectFromGradesAtIndex:(unsigned int)index
    - (void) replaceObjectInGradesAtIndex:(unsigned int)index withObject:
    (id)grade

    Implement these to manipulate your instance variable (which you must
    rename to something other than grades).
    Now all methods of NSMutableArray are applicable to your grades
    property and will automatically generate
    the appropriate key/value observations.  For example

      NSMutableArray *myGrades = [me mutableArrayValueForKey:@"grades"];
      [myGrades removeObject:badGrade];
      [myGrades addObject:goodGrade];

    You might add the following method for aesthetics...

    - (NSMutableArray *) mutableGrades
      { return [self mutableArrayValueForKey:@"grades"]; }

      dave

    On 25-Oct-07, at 7:23 AM, Philip Mötteli wrote:

    > 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 collection (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
    >
  • Am 25.10.2007 um 15:51 schrieb David Spooner:
    >
    > You can expose 'grades' as a to-many property by adding the
    > following methods to Pupil
    >
    > - (unsigned int) countOfGrades
    > - (id) objectInGradesAtIndex:(unsigned int)index
    > - (void) insertObjectInGrades:(id)grade atIndex:(unsigned int)index
    > - (void) removeObjectFromGradesAtIndex:(unsigned int)index
    > - (void) replaceObjectInGradesAtIndex:(unsigned int)index
    > withObject:(id)grade
    >
    > Implement these to manipulate your instance variable (which you
    > must rename to something other than grades).
    > Now all methods of NSMutableArray are applicable to your grades
    > property and will automatically generate
    > the appropriate key/value observations.  For example
    >
    > NSMutableArray *myGrades = [me mutableArrayValueForKey:@"grades"];
    > [myGrades removeObject:badGrade];
    > [myGrades addObject:goodGrade];
    >
    > You might add the following method for aesthetics...
    >
    > - (NSMutableArray *) mutableGrades
    > { return [self mutableArrayValueForKey:@"grades"]; }

    Thanks for these really interesting points!
    What would you do, if you just want to be notified, when an object
    has been added or removed from some NSMutableArray?

    Thanks
    Phil

    >
    > On 25-Oct-07, at 7:23 AM, Philip Mötteli wrote:
    >
    >> 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 collection (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
    >>
    >
  • You can't. An NSMutableArray is a self-contained object for storing an
    array. The documentation on it explicitly states that -
    addObsever:forKey is not supported by it for this reason. You must
    observe it through the use of appropriate accessor methods on another
    object (as in the example below). That is why it is "key" value
    observing.

    Mike.

    P.S. I should point out that you don't have to implement all of the
    methods below. This would suffice:

    - (NSArray *)grades
    - (void)insertObjectInGrades:(id)grade atIndex:(unsigned int)index
    - (void)removeObjectFromGradesAtIndex:(unsigned int)index

    On 25 Oct 2007, at 15:21, Philip Mötteli wrote:

    > Am 25.10.2007 um 15:51 schrieb David Spooner:
    >>
    >> You can expose 'grades' as a to-many property by adding the
    >> following methods to Pupil
    >>
    >> - (unsigned int) countOfGrades
    >> - (id) objectInGradesAtIndex:(unsigned int)index
    >> - (void) insertObjectInGrades:(id)grade atIndex:(unsigned int)index
    >> - (void) removeObjectFromGradesAtIndex:(unsigned int)index
    >> - (void) replaceObjectInGradesAtIndex:(unsigned int)index
    >> withObject:(id)grade
    >>
    >> Implement these to manipulate your instance variable (which you
    >> must rename to something other than grades).
    >> Now all methods of NSMutableArray are applicable to your grades
    >> property and will automatically generate
    >> the appropriate key/value observations.  For example
    >>
    >> NSMutableArray *myGrades = [me mutableArrayValueForKey:@"grades"];
    >> [myGrades removeObject:badGrade];
    >> [myGrades addObject:goodGrade];
    >>
    >> You might add the following method for aesthetics...
    >>
    >> - (NSMutableArray *) mutableGrades
    >> { return [self mutableArrayValueForKey:@"grades"]; }
    >
    > Thanks for these really interesting points!
    > What would you do, if you just want to be notified, when an object
    > has been added or removed from some NSMutableArray?
    >
    >
    > Thanks
    > Phil
    >
    >
    >>
    >> On 25-Oct-07, at 7:23 AM, Philip Mötteli wrote:
    >>
    >>> 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 collection (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
    >>>
    >>

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