在NSMutableArray中观察计数

我想要通知,当伯爵,即。 在一个NSArray中的项目数量发生了变化..当然,我不需要这个,如果我在控制添加和删除对象到数组中。 但是我并不是这样,它在业务stream程模型方面发生了不可预测的变化,并且取决于外部因素。 有一些简单优雅的解决scheme吗?

编辑:我正在纠正这个NSMutableArray当然..

你需要使用KVC 。 但如何去做呢? 毕竟,NSMutableArray对于其突变方法或内容更改不是键值编码兼容的。 答案是代理 – 作为子类NS [Mutable]数组太麻烦了。

NSProxy是一个很好的小类,可以用来截获发送到数组的消息,就好像你是一个NSMutableArray,然后将它们转发给一些内部实例。 不幸的是,它也不符合KVC标准,因为KVC的内核生活在NSObject中。 那么我们必须使用它。 示例界面可能如下所示:

 @interface CFIKVCMutableArrayProxy : NSObject { NSMutableArray *_innerArray; } - (NSUInteger)count; - (void)insertObject:(id)anObject atIndex:(NSUInteger)index; - (void)removeObjectAtIndex:(NSUInteger)index; - (void)addObject:(id)anObject; - (void)removeLastObject; - (void)insertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes; - (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject; //… @end 

正如你所看到的,我们模拟了NSMutableArray的接口,这是必要的,因为我们的代理应该像NSMutableArray一样实现所有的东西。 这也使得实现尽可能简单,因为我们可以将select器转发到内部NSMutableArray指针。 为了简洁起见,我只实现两种方法来显示一般大纲的外观:

 @implementation CFIKVCMutableArrayProxy //… - (NSUInteger)count { return _innerArray.count; } - (void)addObject:(id)anObject { [self willChangeValueForKey:@"count"]; [_innerArray addObject:anObject]; [self didChangeValueForKey:@"count"]; } - (void)removeLastObject { [self willChangeValueForKey:@"count"]; [_innerArray removeLastObject]; [self didChangeValueForKey:@"count"]; } @end 

如果你没有机会像这样包装一个数组,然后尝试重新考虑你的代码。 如果外部依赖性迫使你进入这种angular落,请尝试删除它。 解决你自己的工具总是一件坏事。

要观察mutableArray中的变化,需要使用由给定的可变代理对象

  - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key 

这是KVO兼容的,即任何代理对象发送更改将会改变通知。

以下演示课程显示了完整的实施

 @interface DemoClass : NSObject @property (nonatomic) NSMutableArray *items; - (void)addItemsObserver:(id)object; - (void)removeItemsObserver:(id)object; @end @implementation DemoClass - (NSMutableArray *)items; { return [self mutableArrayValueForKey:@"_items"]; } - (void)addItemsObserver:(id)object { [self addObserver:object forKeyPath:@"_items.@count" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil]; } - (void)removeItemsObserver:(id)object { [self removeObserver:object forKeyPath:@"_items.@count" context:nil]; } @end @interface ObservingClass : NSObject @property (nonatomic) DemoClass *demoObject; @end @implementation ObservingClass - (instanstype)init { if (self = [super init]) { _demoObject = [DemoClass new]; [_demoObject addItemsObserver:self]; } return self; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { NSLog(@"is called on demoObject.items.count change"); } - (void)dealloc { [_demoObject removeItemsObserver:self]; } @end 

现在,每当你添加或删除items中的对象,你会看到新的login控制台( observeValueForKeyPath被称为)。

自动合成的ivar _items数组的任何直接改变都将不起作用。

另外请注意,你强烈需要在_items.@count上设置观察者_items.@count (观察items.@count是无意义的)。

请注意,您不需要初始化_itemsself.items 。 当你打电话给items者时,它将在现场完成。

每当你改变“数组” items你将得到新的地址的对象_items 。 但我仍然可以通过items代理getterfind它。