KVO修改由NSMutableArray支持的NSArray的通知
我正在尝试使用KVO来侦听NSArray属性上的集合更改事件。 公开的说,这个属性是一个只读的NSArray,但是由一个NSMutableArray ivar支持,所以我可以修改这个集合。
我知道我可以将属性设置为一个新值来获得“设置”更改,但我有兴趣添加,删除,replace更改。 如何正确地通知NSArray的这些types的更改?
@interface Model : NSObject @property (nonatomic, readonly) NSArray *items; @end @implementation Model { NSMutableArray *_items; } - (NSArray *)items { return [_items copy]; } - (void)addItem:(Item *)item { [_items addObject:item]; } @end
Model *model = [[Model alloc] init]; [observer addObserver:model forKeyPath:@"items" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL]; Item *item = [[Item alloc] init]; [model addItem:newItem];
观察class:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"items"]) { //Not called } }
首先,你应该明白,KVO是用来观察物体的属性变化的 。 也就是说,你不能“观察一个数组”,你会观察到一个索引的集合属性。 该属性可以由数组支持或以其他方式实现。 只要符合KVC标准并按照KVO标准进行修改,就足够了。 (所以,如果属性的types是NSArray*
或者使用NSMutableArray*
或其他types来实现,则无关紧要。)
所以,你正在观察一个Model
的实例来更改它的items
属性。 如果您希望观察者获得更改通知,则必须始终以符合KVO的方式修改items
属性。
在我看来,最好的办法是实现可变索引的集合访问器,并总是使用它们来修改属性。 所以,你至less要实现其中一个:
- (void) insertObject:(id)anObject inItemsAtIndex:(NSUInteger)index; - (void) insertItems:(NSArray *)objects atIndexes:(NSIndexSet *)indexes;
其中之一:
- (void) removeObjectFromItemsAtIndex:(NSUInteger)index; - (void) removeItemsAtIndexes:(NSIndexSet *)indexes;
当属性由NSMutableArray
支持时,上述方法是围绕_items
上相应方法的直接包装。
你写任何其他方法来修改你的财产应该通过其中之一。 所以,你的-addItem:
方法是:
- (void)addItem:(Item *)item { [self insertObject:item inItemsAtIndex:[_items count]]; }
您也可以删除items
属性的普通getter,而只是公开索引集合获得者:
- (NSUInteger) countOfItems; - (id) objectInItemsAtIndex:(NSUInteger)index;
如果有一个典型的getter,那不是必须的。
(这些访问器的存在允许你实现一个非NSArray
types的to-many属性,从KVC的angular度来看,对于任何实际的数组types的接口是没有必要的)。
就个人而言,我不build议这样做,但是一旦有了这样的访问器,也可以通过使用-mutableArrayValueForKey:
获取属性的-mutableArrayValueForKey:
NSMutableArray
的代理来改变属性,然后向其发送变异操作。 所以,在这种情况下,你可能会[[self mutableArrayValueForKey:@"items"] addObject:item]
。 我不喜欢这个,因为我觉得键值编码适用于密钥是数据的情况。 它是dynamic的或存储在数据文件中,如NIB,在编译时不知道。 当你有select使用语言符号(例如select器)来解决属性的硬编码键名称是一种代码异味。
但是,对于那些在索引访问方面真正曲折的操作,比如分类,这是可以certificate的。
最后,您可以使用NSKeyValueObserving
协议的-willChange...
和-didChange...
方法在直接修改属性的后备存储时发出更改通知,而无需通过KVO可以识别并挂接的突变方法。 对于索引集合属性,这将是-willChange:valuesAtIndexes:forKey:
和-didChange:valuesAtIndexes:forKey:
方法。 就我而言,这是一种更糟糕的代码味道。
- 使用KVO与NSNotificationCenter观察对可变arrays的更改
- UITextField initWithFrame上的KVO崩溃
- mergeChangesFromContextDidSaveNotification之后的KVO通知
- KVO在iOS 9.3中破解
- 这个observeValueForKeyPath有什么问题:ofObject:change:context:implementation?
- 我怎样才能做关键值观察,并得到一个UIView帧的KVOcallback?
- 在Swift的计算属性上的KVO
- KVO与NSNotifications
- UIWindow RootViewController更改SWIFT时触发事件/方法