如果我更改了一个属性的值,KVO会帮助我们检测这个值的变化,从而通知我们这个值改变了。典型的观察者模式。当然我想起在UNITY3D中,如果检视面板的数值发生改变对应的GameObject发生位移之类的。我曾经实现了一个inspector的编辑器类,值改变直接通知(其实是调用)对应的函数。在iOS这里 一切发生的那么自然。不需要额外实现 这是iOS的特性之一 名曰:KVO 。
前情提要 上一篇 KVC 讲到需要遵循的几条几本规则在 KVO 中同样适用。
骆驼命名法,不能数字开头
不能包含空格
键必须是ASCII编码的
使用默认的get/set
上一章 只要是针对 object 的元素查询,调用,筛选。本文主要是讲述 KVO 监听(观察者模式) 属性值的变更。
添加/移除 一个监听 addObserver 函数签名如下
addObserver:监听的接受脚本的类
context: 随便传入任何值都可以,最后取出来的时候需要强转
forKeyPath: 选择一个需要监听的属性
options: 可选项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #import <Foundation/Foundation.h> #import "Foo.h" #import "Bar.h" int main(int argc, const char * argv[]) { Foo* foo = [[Foo alloc]init]; foo.bar = [[Bar alloc]init]; [foo.bar addObserver:foo forKeyPath:@"stringOnBar" options:0 context: (void *)s]; foo.bar.stringOnBar = @"test" ; [foo.bar removeObserver:foo forKeyPath:@"stringOnBar" ]; return 0 ; }
控制台输出如下:
1 2 3 2017 -03 -03 15 :17 :22.085142 oc[52721 :6279405 ] helloworld2017 -03 -03 15 :17 :22.085371 oc[52721 :6279405 ] Value Changed : stringOnBarProgram ended with exit code: 0
关于 options 可选项 上面的代码中 options 是个可选项,这里不需要处理所以填写0,详细的选项如下:
1 2 3 4 5 NSKeyValueObservingOptionNew 把更改之前的值提供给处理方法NSKeyValueObservingOptionOld 把更改之后的值提供给处理方法NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。NSKeyValueObservingOptionPrior 分2 次调用。在值改变之前和值改变之后。0 不带任何参数进去
传递给监听的值在接受函数 ofObject:(id)object
可以获取到。
关于监听脚本 不用担心监听脚本过于复杂。其实是自动生成的 键入 observeValueForKeyPath 则会生成如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 - (void )observeValueForKeyPath:(NSString *)keyPath ofObject:(id )object change:(NSDictionary *)change context:(void *)context { NSString * content = (__bridge NSString *)context; if (content) { NSLog (@"%@" ,content); } if ([keyPath isEqualToString:@"stringOnBar" ]) { NSLog (@"Value Changed : stringOnBar" ); return ; } if ([keyPath isEqualToString:@"stringOnFoo" ]) { NSLog (@"Value Changed : stringOnFoo" ); return ; } [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; }
当然结构体里面的内容是我自己些的 😄
当类 dealloc 的时候需要手动移除监听,否则会报错 … 报错信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2017 -03 -03 15 :16 :02.560251 oc[52593 :6273946 ] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException' , reason: 'An instance 0x1004065e0 of class Bar was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x100406b90> ( <NSKeyValueObservance 0x100407e80: Observer: 0x1004045e0, Key path: stringOnBar, Options: <New: NO, Old: NO, Prior: NO> Context: 0x1000030c0, Property: 0x100406ac0> )' *** First throw call stack: ( 0 CoreFoundation 0x00007fffa311fe7b __exceptionPreprocess + 171 1 libobjc.A.dylib 0x00007fffb7d09cad objc_exception_throw + 48 2 CoreFoundation 0x00007fffa319e99d +[NSException raise:format:] + 205 3 Foundation 0x00007fffa4aff6e4 NSKVODeallocate + 293 4 oc 0x000000010000278e -[Foo .cxx_destruct] + 78 5 libobjc.A.dylib 0x00007fffb7d05686 _ZL27object_cxxDestructFromClassP11objc_objectP10objc_class + 127 6 libobjc.A.dylib 0x00007fffb7cfe0c6 objc_destructInstance + 92 7 libobjc.A.dylib 0x00007fffb7cfe059 object_dispose + 22 8 oc 0x000000010000166e main + 398 9 libdyld.dylib 0x00007fffb85ed255 start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)
手动KVO KVO不是万能的,有时候我们在某些条件下不希望接受到KVO的通知,需要重写如下方法:
1 2 3 4 5 6 7 NSInteger HP = 10 ;+(BOOL )automaticallyNotifiesObserversOfStringOnFoo { if (HP>100 ) return YES ; return NO ; }
这里有一个技巧输入 +(BOOL)automatically
之后自动列出可以重写的几个属性的通知。
手动触发KVO也是允许的,下面主要使用到了 willChangeValueForKey / didChangeValueForKey
这两个函数。即使禁止了自动通知也可以直接在get函数中触发。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 NSInteger HP = 11 ;+(BOOL )automaticallyNotifiesObserversOfStringOnFoo { if (HP>100 ) return YES ; return NO ; } -(void )setStringOnFoo:(NSString *) inValue { [self willChangeValueForKey:@"stringOnFoo" ]; stringOnFoo = inValue; [self didChangeValueForKey:@"stringOnFoo" ]; }
本文标题: KVO in iOS
文章作者: Keyle
发布时间: 2017-03-02
最后更新: 2024-08-20
原始链接: https://vrast.cn/posts/d0d6deab/
版权声明: ©Keyle's Blog. 本站采用署名-非商业性使用-相同方式共享 4.0 国际进行许可