以前有個需求,需要監聽數組長度的變化。使用KVO直接監聽數組本身,由於數組地址並沒有發生改變,所以並不能監聽到。試了好多方法,都沒有能夠實現。知道最近聽的一場公開課中,才掌握了正確的監聽方法
先舉個錯誤的例子
@interface ViewController () @property (nonatomic, strong) NSMutableArray *array; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self.array addObserver:self forKeyPath:@"count" options:(NSKeyValueObservingOptionNew) context:nil]; }
這樣會直接報錯,NSMutableArray 沒有 count的 keyPath。
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '[<__NSArrayM 0x282195770> addObserver:forKeyPath:options:context:] is not supported. Key path: count'
正確的打開方式是這樣的,不多說廢話,直接上代碼
#import "ViewController.h" @interface ViewController () @property (nonatomic, strong) NSMutableArray *array; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self addObserver:self forKeyPath:NSStringFromSelector(@selector(array)) options:(NSKeyValueObservingOptionNew) context:nil]; } - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context { /* typedef NS_ENUM(NSUInteger, NSKeyValueChange) { NSKeyValueChangeSetting = 1, NSKeyValueChangeInsertion = 2, NSKeyValueChangeRemoval = 3, NSKeyValueChangeReplacement = 4, }; */ //第一次觸發是添加一條數據,kind為2,對應的是NSKeyValueChangeInsertion /* { indexes = "<_NSCachedIndexSet: 0x280495620>[number of indexes: 1 (in 1 ranges), indexes: (0)]"; kind = 2; new = ( "NewData- 1" ); } */ //第二次觸發是修改一條數據,kind為4,對應的是NSKeyValueChangeReplacement /* { indexes = "<_NSCachedIndexSet: 0x280495620>[number of indexes: 1 (in 1 ranges), indexes: (0)]"; kind = 4; new = ( "NewData- 2" ); } */ //第三次次觸發是刪除一條數據,kind為3,對應的是NSKeyValueChangeRemoval /* { indexes = "<_NSCachedIndexSet: 0x280495620>[number of indexes: 1 (in 1 ranges), indexes: (0)]"; kind = 3; } */ NSLog(@"我觸發了"); } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { static NSInteger a = 0; a++; //這一步特別重要 NSMutableArray *tempArray = [self mutableArrayValueForKey:NSStringFromSelector(@selector(array))]; if (1 == a) {//插入一條 [tempArray addObject:[NSString stringWithFormat:@"NewData- %tu",a]]; } else if (2 == a) {//修改一條 tempArray[0] = [NSString stringWithFormat:@"NewData- %tu",a]; } else if (3 == a) { [tempArray removeAllObjects]; } } - (NSMutableArray *)array { if (!_array) { _array = [NSMutableArray array]; } return _array; } - (void)dealloc { [self removeObserver:self forKeyPath:NSStringFromSelector(@selector(array))]; }
KVO三部曲,注冊監聽,實現代理方法,移除監聽。
在監聽數組變化時,需要特別注意,
NSMutableArray *tempArray = [self mutableArrayValueForKey:NSStringFromSelector(@selector(array))];
一定要使用該方法復制出一個數組,而不是使用數組本身進行操作。