欢迎来到夜场招聘网!

KVO 取 readonly的探讨 (数组array & setter) iOS

来源:夜店招聘网 时间:2019-08-14 作者:夜店招聘网 浏览量:

在开发过程中,可能会有这样的需求:当数据源变动的时候及时刷新显示的列表。期望是去监听数据源数组的Count,当Count有变动就刷新UI,可是实际操作中却发现了不少的问题。例如:
self.propertyArray=[NSMutableArrayarray];[self.propertyArrayaddObserver:selfforKeyPath:@"Count"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:nil];
直接就报错了,信息如下:
Terminating app due to uncaught exception ´NSInvalidArgumentException´, reason: ´[<__NSArrayM Ox6000033db450> addObserver:forKeyPath:options:context:] is not supported. Key path: Count´
字面意思是,不支持对数组Count的监听。回到问题的本质。我们知道KVO是在属性的setter方法上做文章,进入到数组的类中看一下,发现Count属性是readonly
@interfaceNSArray<__covariantobjectType>:NSobject@property(readonly)NSUIntegerCount;
readonly不会自动生成setter方法,但是可以手动添加setter方法。我们来验证一下 例如:创建一个people类 添加一个属性 readonly Count
@interfacePeople:NSobject@property(nonatomic,readonly)NSIntegerCount;@end@implementationPeople@end
我们来试一下 监听它的Count属性会怎样
People*peo=[Peoplenew];[peoaddObserver:selfforKeyPath:@"Count"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:nil];
我们发现 并没有报错。我们来看一下People的方法列表
constchar*className="People";ClassNSKVONotifying_People=objc_getClass(className);unsignedintmethodCount=0;Method*methodList=class_copyMethodList(NSKVONotifying_People,&methodCount);NSMutableArray*methodsArray=[NSMutableArrayarrayWithCapacity:methodCount];for(inti=0;iject:[NSStringstringWithUTF8String:name_s]];}NSLog(@"%@",methodsArray);
通过打印我们可以看到 People中只有两个方法
(dealloc,Count,)
我们知道,KVO监听某个对象时,会动态生成名字叫做NSKVONotifying_XX的类,并且重写监听对象的setter方法。下面 我们来看下NSKVONotifying_People的方法列表:
constchar*className="NSKVONotifying_People";ClassNSKVONotifying_People=objc_getClass(className);unsignedintmethodCount=0;Method*methodList=class_copyMethodList(NSKVONotifying_People,&methodCount);NSMutableArray*methodsArray=[NSMutableArrayarrayWithCapacity:methodCount];for(inti=0;iject:[NSStringstringWithUTF8String:name_s]];}NSLog(@"%@",methodsArray);
打印结果如下:
(class,dealloc,"_isKVOA")
可以看到,里面没有Count的getter方法,多了个class和isKVO, 当然也没有我们需要的setter方法。但是这样并不会导致crash。
下面我们再试一下,手动在People的.m中 添加上setter方法会怎么样:
@implementationPeople-(void)setCount:(NSInteger)Count{_Count=Count;}@end
再次查看People和NSKVONotifying_People的方法列表,会发现多了一个Count的setter方法。(如下所示)
(dealloc,Count,"setCount:")("setCount:",class,dealloc,"_isKVOA")
这样我们就可以得出一个结论:KVO动态生成的类,重写setter方法的前提是:原来的类中,要有对应的setter方法。即便是readonly修饰,只要.m中有对应属性的setter方法,都是可以的。
OK 说了这么多,好像还是没有解决我们的问题。为什么监听数组Count就抛异常了呢?带着这个问题 继续往下走。通过点击array的监听方法 进入到ArrayObserving类中,我们发现,系统给出了注释:NSArrays are not observable, so these methods raise exceptions when invoked on NSArrays.
arrayDefin.png
系统也不期望我们去监听数组的属性。is not supported. Key path: Count´ 应该就是系统在实现监听方法时,抛出的异常。
最后,我从网上找到了另一个方法
[selfmutableArrayValueForKey:@"propertyArray"]
我们可以转换一个思路,不再监听Count,选择监听数组本身,当数组变动时刷新页面。
[selfaddObserver:selfforKeyPath:@"propertyArray"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:nil];[[selfmutableArrayValueForKey:@"propertyArray"]addobject:@"a"];
这个方法的具体实现,没有看到源码,但是看到有人说,这个方法会生成一个可变数组,添加完元素后,会将这个生成的数组赋值给叫做Key的数组。我试了一下,确实是有效果的,这里就不做考究了。
热门话题
推荐文章
最新文章

Copyright C 2018 All Rights Reserved 版权所有 午夜招聘网

微信扫一扫