扬庆の博客

KVO

字数统计: 1.3k阅读时长: 5 min
2022/03/31 Share

KVO

key value observing 键值监听。当指定对象的属性被修改后,允许对象接收到通知的机制。

又叫作观察者模式 KVO

先看下面 kvo 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//
// ViewController.swift
// testKVO
//
// Created by dayu on 2022/2/25.
//

import UIKit
// Swift里KVO不需要像OC里那样手动释放,系统自动释放。
// 要监听的类需要使用@objcMembers 修饰,否则可能无法触发。
// 要监听哪个属性,哪个属性就要用dynamic进行修饰,否则不会触发回调。

@objcMembers class MyNumber: NSObject {
dynamic var number : Int = 1
}

class ViewController: UIViewController {

var testNum: MyNumber!

deinit {
testNum.removeObserver(self, forKeyPath: "value")
}

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.

testNum = MyNumber.init()
testNum.addObserver(self, forKeyPath: "number", options: [.old, .new], context: nil)
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touch began")
testNum.number += testNum.number
}



override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

if let old = change?[.oldKey] {
print("old value is: \(old)")
}

if let new = change?[.newKey] {
print("the new value is \(new)")
}
}

}


看了上面的代码我们再来研究一下什么事KVO

KVO

==键值监听==

当我想知道==一个对象的属性是否发生改变的时候==,做出响应;就需要添加监听。

关键字

keypath key的区别。

==keypath自动寻找子类的属性。==

==key只会寻找当前类的属性==。

  • 添加键值监听 someObject.addObserver: keyPath:
  • 键值发生改变 observerValueForKeyPath:
  • 移除监听 someObject.removeObserver:ForKey:

OC中使用KVO

OC中KVO调用方式出了上面修饰符其他都一样

1
2
3
4
5
6
7
8
9
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath 
options:(NSKeyValueObservingOptions)options
context:(void *)context;

- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object change:(NSDictionary *)change context:(void *)context;

- (void)removeObserver:(NSObject *)observer
forKeyPath:(NSString *)keyPath;

那什么是KVO?

上面了解了KVO是键值监听。

那么什么是kvo,解决了什么问题呢? 或者是什么场景下需要KVO?KVO的优缺点是什么?

  • 解决了什么问题

使得观察者与被观察者完全 ==解藕== 。

  • 使用场景

1.使用KVO实现滑动scrollerView里对NavigationBar颜色的渐变;

2.检测进度条

3.上拉加载下拉刷新;

一般KVO的场景是数据,需求时数据变化,比如股票价格的变化。

https://www.jianshu.com/p/8f23536de9d4

KVO的优缺点

  • 优点
  1. ==能够提供一种简单的方法实现两个对象间的同步==; 例如:model和View之间的同步。

  2. 能够对非我们创建的对象,即内部对象的状态改变作出响应, 而且不需要改变内部对象。

  3. 能够提供观察的属性的最新值new以及先前值old。

  4. 用key Paths来观察属性,因此也可以观察嵌套对象。

  5. 完成了对观察对象的抽象,因为不需要额外的代码来允许观察值能够被观察。

  • 缺点
  1. 我们==观察的属性必须使用string来定义==。因此在编译时不会出现警告以及检查;
  2. 对属性重构将导致我们的观察代码不再可用。
  3. 复杂的if语句要求对象正在观察多个值,是因为所有的观察代码通过一个方法来指向。
  4. 释放观察者时不需要移除观察者。

总结

1
2
3
4
(被观察者testNumb).addObserver(观察者self, forKeyPath: 被观察的属性numb, options: 被观察的选项 new, old, context: 一般写nil)

被观察者testNumb.removeObserver(观察者self, forKeyPath: 被观察的属性)

被观察者: 需要监听观察的对象,观察内部属性的值变化然后作出响应。观察者: 观察到被观察对象属性变化, 作出响应/反应。

通过上面两句可以看出KVO好处能够将观察者和被观察者完全解藕,运用灵活。但是KVO只能检测类中的属性,并且属性名都是通过String类型来查找,编译器不会不全,容易写错。

KVO和Notification的区别。

相同点

  1. NSNotification 和KVO都是==类与类之间的通信==。
  2. 都是负责发出通知,剩下的事情不用管了。
  3. 两者都可以一对多。

不同点

  1. KVO的使用

    1. 被观察者addObserver来添加观察者。
    2. 只要被观察者的keyPath值变化(==只有通过getter和setter方法改变值才会触发KVO==),就会在观察者里面调用方法ObserveValueForKey Path:ofObject:change:context: 观察者需要实现这个方法来对KVO发出的通知作出响应。
    3. KVO只能检测类中的属性,并且属性名都是通过String/NSString来查找,编译器不会不全,容易出错。
  2. NSNotification的使用

    1. 一对多,app中很多控制器都需要知道一个事件,应该用通知。
    2. 通知不是由被观察者(例如:testNumber)发出的,而是==NSNoticicationCenter(通知中心)统一发出==的,不同通知通过唯一的通知标识名notificationName来区分。
    3. 需要==被观察者主动发出通知==,然后观察者注册监听后再来进行响应,比KVO多了一个发送通知的步骤,但是优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,==监听范围广,使用更灵活==。

面试相关问题?

  1. KVO本质?
  2. 如何手动触发KVO?
  3. 直接修改成员变量会触发KVO吗?

原文作者:杨庆

原文链接:http://www.yqblog.cn/2022/03/31/KVO/

发表日期:March 31st 2022, 6:47:49 pm

更新日期:April 19th 2022, 11:47:39 pm

版权声明:本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可

CATALOG
  1. 1. KVO
    1. 1.0.1. KVO
      1. 1.0.1.1. 关键字
    2. 1.0.2. OC中使用KVO
  2. 1.1. 那什么是KVO?
    1. 1.1.1. KVO的优缺点
    2. 1.1.2. 总结
  • 2. KVO和Notification的区别。
    1. 2.0.1. 相同点
    2. 2.0.2. 不同点
    3. 2.0.3. 面试相关问题?