Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should observers be notified when insertObject:in<Key>AtIndex: is called?

I have a model tied to an array controller. I need to be able to update the model directly and have notifications sent to the array controller about the update. In my searching I found that I could accomplish this by using mutableArrayValueForKey: on my model and updating through the returned NSMutableArray.

I also found several references that led me to believe that I could also update the model and have notifications sent if I implemented and used the KVC compliant getter and mutable indexed accessors. In my code I implemented

-countOf<Key>:
-objectIn<Key>AtIndex:
-insertObject:in<Key>AtIndex:
-removeObjectFrom<Key>AtIndex:

Calling insertObject:in<Key>AtIndex: did not result in my observers being notified. The code below is the smallest piece I could come up with to test what I was trying to do.

#import <Foundation/Foundation.h>

@interface ModelAndObserver : NSObject {
  NSMutableArray *theArray;
}

@property(retain)NSMutableArray *theArray;

- (NSUInteger)countOfTheArray;
- (NSString *)objectInTheArrayAtIndex:(NSUInteger)index;
- (void)insertObject:(NSString*) string inTheArrayAtIndex:(NSUInteger)index;
- (void)removeObjectInTheArrayAtIndex:(NSUInteger)index;
@end

@implementation ModelAndObserver
@synthesize theArray;

- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary *)change 
                       context:(void *)context
{
  NSLog(@"theArray now has %d items", [theArray count]);
}

- (NSUInteger)countOfTheArray
{
  return [theArray count];
}

- (NSString *)objectInTheArrayAtIndex:(NSUInteger)index
{
  return [theArray objectAtIndex:index];
}

- (void)insertObject:(NSString*) string inTheArrayAtIndex:(NSUInteger)index
{
  [theArray insertObject:string atIndex:index];
}

- (void)removeObjectInTheArrayAtIndex:(NSUInteger)index
{
  [theArray removeObjectAtIndex:index];
}

@end


int main (int argc, const char * argv[]) {
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

  ModelAndObserver *mao = [[ModelAndObserver alloc] init];

  [mao addObserver:mao 
        forKeyPath:@"theArray" 
           options:0 
           context:@"arrayChanged"];

  // This results in observeValueForKeyPath... begin called.
  [mao setTheArray:[NSMutableArray array]];

  // This results in observeValueForKeyPath... begin called.
  [[mao mutableArrayValueForKey:@"theArray"] addObject:@"Zero"];

  // These do not results in observeValueForKeyPath... 
  // begin called, but theArray is changed.
  [mao insertObject:@"One" inTheArrayAtIndex:1];
  [mao insertObject:@"Two" inTheArrayAtIndex:2];
  [mao insertObject:@"Three" inTheArrayAtIndex:3];

  // This results in observeValueForKeyPath... begin called.
  [[mao mutableArrayValueForKey:@"theArray"] addObject:@"Four"];


  [mao removeObserver:mao forKeyPath:@"theArray"];
  [mao release];
  [pool drain];
  return 0;
}

When I run this code I get the following output:

2011-02-05 17:38:47.724 kvcExperiment[39048:a0f] theArray now has 0 items
2011-02-05 17:38:47.726 kvcExperiment[39048:a0f] theArray now has 1 items
2011-02-05 17:38:47.727 kvcExperiment[39048:a0f] theArray now has 5 items

I was expecting to see three more log messages that say theArray now has 2, 3, or 4 items. I thought the calling insertObject:inTheArrayAtIndex should have notified the obvserver that theArray has changed, but in my code it is not.

Am I confused in thinking that insertObject:inTheArrayAtIndex should result in a notification being sent to the observers of theArray? Or, did I miss something in my implementation? Any help is appreciated.

like image 700
Paul Heely Avatar asked Jan 21 '23 13:01

Paul Heely


1 Answers

It's because you didn't implement both the insert and the remove method.

“What!”, you say. “I did too!”

No, not quite. Almost, but you got a word wrong: It's removeObjectFromTheArrayAtIndex:.

With that fix applied, all six changes cause observer notifications.

like image 167
Peter Hosey Avatar answered Jan 31 '23 10:01

Peter Hosey