小编这次要给大家分享的是详解在Swift中使用KVO,文章内容丰富,感兴趣的小伙伴可以来了解一下,希望大家阅读完这篇文章之后能够有所收获。

在文字的开头,先说一个小细节,swift中声明一个类,你可以集成自NSObject,也可以选择忽略,二者有什么区别呢。根据自己的经验,我得出以下结论。不足之处,请指出。exmple:我们声明这样一个类

class Person: NSObject { var name: String? override init() { super.init() }}此类打印出的内存地址是0x00000fbd00007ffeefbfc240

这段代码是不会报错的,是一个典型的swift遗留ObjC语法的写法,但是如果我们去掉NSObject并打印出他的内存地址,如下

class Person { var name: String? init() { }}此类打印出的内存地址是0x00007ffeefbfc240内存地址不一样,继承自NSObject的类对象的内存地址明显长度多了8个长度,why?多出的8个空间就是为了存放ObjC对象内的isa指针,有兴趣的可以往下研究。继承自NSObject的类可以使用OC里的一些骚操作,比如KVC、KVO、runtime,否则使用setValue-forKey时是会报错的。

区别还有很多,平时在开发中大家可以多注意这一区别。个人偏向不继承NSObject,尤其是我需要此类做一些骚操作时,比如KVO。

KVO是OC一个对象属性的特性,由于是面向字符串,所以开发时需要尤其小心,这种奔溃只有执行到了才会报错。声明如下类:

class Person: NSObject { @objc var age: Int? var name: String? var observation: NSKeyValueObservation? override init() { super.init() self.observation = observe(\Person.age, options: .new, changeHandler: { (person, change) in print("Person.age的新值 = ", change.newValue as Any) }) }}

在外部我们,初始化一个对象,并对age进行赋值,如下

let person = Person()person.age = 18person.setValue(100, forKey: "age")

程序执行后,(ÒωÓױ)!为什么只有一个打印?按理说是应该打印Person.age的新值 = 18Person.age的新值 = 100的呀,然而并没有:laughing:。问题出在哪,原来,swift中如果需要对一个值进行监听,那么一定要记住2个关键词

@objcdynamic

否则,

没有@objc程序在监听时会触发奔溃;没有dynamic则属性的set方法不会生效,自然就没有上面的打印,因为KVO的本质就是监听属性的set方法,而可变数组的增删操作都不会生效;

但是为什么KVC的操作却能生效呢?这是因为KVC内部的实现过程是

[person willChangeValueForKey:@"age"];person->_age = 10;[person didChangeValueForKey:@"age"];而didChangeValueForKey:内部会调用observe的observeValueForKeyPath:ofObject:change:context:的方法,也就触发了KVO

所以正确的写法应该是

class Person: NSObject { @objc dynamic var age: Int? var name: String? var observation: NSKeyValueObservation? override init() { super.init() self.observation = observe(\Person.age, options: .new, changeHandler: { (person, change) in print("Person.age的新值 = ", change.newValue as Any) }) }}

看完这篇关于详解在Swift中使用KVO的文章,如果觉得文章内容写得不错的话,可以把它分享出去给更多人看到。