在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
是无意义的)。
请注意,您不需要初始化_items
或self.items
。 当你打电话给items
者时,它将在现场完成。
每当你改变“数组” items
你将得到新的地址的对象_items
。 但我仍然可以通过items
代理getterfind它。