在Swift中使用KVO的细节以及内部实现解析(推荐)

 更新时间:2020年07月21日 10:00:34   作者:雨人在掘金  
这篇文章主要介绍了在Swift中使用KVO的细节以及内部实现解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

KVO是什么?

KVO 是 Objective-C 对观察者设计模式的一种实现。【另外一种是:通知机制(notification),详情参考:iOS 趣谈设计模式——通知】;
KVO提供一种机制,指定一个被观察对象(例如A类),当对象某个属性(例如A中的字符串name)发生更改时,对象会获得通知,并作出相应处理;【且不需要给被观察的对象添加任何额外代码,就能使用KVO机制】
在MVC设计架构下的项目,KVO机制很适合实现mode模型和view视图之间的通讯。

例如:代码中,在模型类A创建属性数据,在控制器中创建观察者,一旦属性数据发生改变就收到观察者收到通知,通过KVO再在控制器使用回调方法处理实现视图B的更新;(本文中的应用就是这样的例子.)

实现原理?

KVO在Apple中的API文档如下:

Automatic key-value observing is implemented using a technique called isa-swizzling… When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class …
KVO 的实现依赖于 Objective-C 强大的 Runtime【可参考:Runtime的几个小例子】 ,从以上Apple 的文档可以看出苹果对于KVO机制的实现是一笔带过,而具体的细节没有过多的描述,但是我们可以通过Runtime的所提供的方法去探索,关于KVO机制的底层实现原理。为此啊左从网上的一些关于KVO的资料总结了有关的内容:

基本的原理:

当观察某对象A时,KVO机制动态创建一个对象A当前类的子类,并为这个新的子类重写了被观察属性keyPath的setter 方法。setter 方法随后负责通知观察对象属性的改变状况。

好了,下面本文重点内容:

在文字的开头,先说一个小细节,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 = 18
person.setValue(100, forKey: "age")

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

  • @objc
  • dynamic

否则,

没有@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的细节以及内部实现解析的文章就介绍到这了,更多相关Swift使用KVO内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • swift如何利用系统库将汉字转换为拼音详解

    swift如何利用系统库将汉字转换为拼音详解

    将汉字转换为拼音更利于我们大家开发搜索功能,所以这篇文章主要给大家介绍了关于swift如何利用系统库将汉字转换为拼音的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-10-10
  • Switch语句的技巧

    Switch语句的技巧

    switch语句对一个表达式求值,将结果与 case 子语句比较,如果匹配,则从 case 处的语句向下执行,本文给大家介绍Switch语句的技巧,需要的朋友参考下吧
    2016-02-02
  • Swift TableView实现冻结窗格功能

    Swift TableView实现冻结窗格功能

    这篇文章主要为大家详细介绍了Swift TableView实现冻结窗格功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • swift4 使用DrawerController实现侧滑菜单功能的示例代码

    swift4 使用DrawerController实现侧滑菜单功能的示例代码

    这篇文章主要介绍了swift4 使用DrawerController实现侧滑功能的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • swift版webview加载网页进度条效果

    swift版webview加载网页进度条效果

    这篇文章主要为大家详细介绍了swift实现webview加载网页进度条效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • swift实现颜色渐变以及转换动画

    swift实现颜色渐变以及转换动画

    这篇文章主要为大家详细介绍了swift实现颜色渐变以及转换动画,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • 详细讲解Swift中的类型占位符

    详细讲解Swift中的类型占位符

    类型占位符是swift5.6中引⼊的⼀个新功能,在处理稍微复杂的通⽤类型时,它可能真的很有用,这篇文章主要给大家介绍了关于Swift类型占位符的相关资料,需要的朋友可以参考下
    2022-06-06
  • Swift中图片资源使用流程的优化方法详解

    Swift中图片资源使用流程的优化方法详解

    这篇文章主要给大家介绍了关于Swift中图片资源使用流程的优化方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-01-01
  • Swift如何为网页承载页面添加更多功能详解

    Swift如何为网页承载页面添加更多功能详解

    这篇文章主要给大家介绍了关于Swift如何为网页承载页面添加更多功能的相关资料,包括添加菊花加载的效果、添加跳转到Safari的功能、添加复制链接的功能以及添加分享网页的功能,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2018-05-05
  • Swift 3.0基础学习之枚举类型

    Swift 3.0基础学习之枚举类型

    枚举在编程中很多时候要用到,在 Swift 中,枚举具有更多的特性。下面这篇文章主要介绍了Swift 3.0基础学习之枚举类型的相关资料,文中介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-03-03

最新评论