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.
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 removeObject
From
TheArrayAtIndex:
.
With that fix applied, all six changes cause observer notifications.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With