iOS KVO隐藏用法与核心潜力解析
时间:2026-08-21 | 作者:星际追番人 | 阅读:0概述
在iOS开发领域,KVO(Key-Value Observing,键值观察)是一种很强大的观察者模式实现。它能够让对象监听其他对象特定属性的变化。
一旦被观察的属性发生变动,观察者就会立刻收到通知。接下来,本文将对KVO的原理、使用方式、注意事项以及优缺点展开探讨。
KVO核心机制
KVO本质是通过 isa-swizzling技术实现的。具体过程可以分为以下几步。
1.动态子类创建
- 当某个对象第一次被观察时,运行时系统会动态创建该对象类的子类,子类命名通常为
NSKVONotifying_原类名 - 为
NSKVONotifying_原类名重写观察属性的setter方法以及delloc、class、_isKVOA方法等
2.settter方法重写
- 在赋值前调用
willChangeValueForKey - 在赋值后调用
didChangeValueForKey
// KVO 的伪代码实现
- (void)setName:(NSString *)name {
// 1.通知属性即将变化
[self willChangeValueForKey:@"name"];
// 2.调用原始的 setter 方法
_name = name;
// 3.通知属性已经变化
[self didChangeValueForKey:@"name"];
}
- 子类重写
class方法是为了屏蔽本身,隐藏其存在,不让开发者知道- 当修改实例对象的属性时,会调用
Foundation的_NSSetXXXValueAndNotify函数
3.修改isa指针
- 运行时系统会将原对象的
isa指针指向新创建的子类(NSKVONotifying_MyClass) - 通过修改
isa指针,对象的实际类型变为子类,从而使得调用setter方法时,会优先调用子类中重写的setter方法
使用方式
Objective-C
下面是Objective-C中的基本使用示例。
@interface Person : NSObject
@property (nonatomic, assign) NSInteger age;
@end
@implementation Person
@end
@interface ViewController ()
@property (nonatomic, strong) Person *person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 创建 Person 对象
self.person = [[Person alloc] init];
self.person.age = 20;
// 注册 KVO
[self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
// 修改 age 属性的值
self.person.age = 30;
}
// 实现观察者的回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"age"]) {
NSInteger oldValue = [[change objectForKey:NSKeyValueChangeOldKey] integerValue];
NSInteger newValue = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
NSLog(@"Person's age changed from %ld to %ld", oldValue, newValue);
}
}
// 在不需要监听属性变化时,我们应该及时移除 KVO
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// 移除 KVO
[self.person removeObserver:self forKeyPath:@"age"];
}
@end
Swift
下面是Swift中的使用方式。
class Person: NSObject {
@objc dynamic var age: Int
init(age: Int) {
self.age = age
}
}
class ViewController: UIViewController {
private var person = Person(age: 20)
private var ageObserver: NSKeyValueObservation
override func viewDidLoad() {
super.viewDidLoad()
// 注册 KVO
ageObserver = person.observe(.age, options: [.old, .new], changeHandler: { [weak self] (person, change) in
guard let self = self else { return }
if let oldValue = change.oldValue, let newValue = change.newValue {
print("Person's age changed from (oldValue) to (newValue)")
}
})
// 修改 age 属性的值
person.age = 30
}
}
func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
ageObserver.invalidate()
ageObserver = nil
}
注意,为了在
Swift中使用KVO,我们需要在age属性前加上@objc dynamic修饰符。这样才能使age属性具有动态派发的特性,从而支持KVO
KVO “搞笑”时刻
KVO好用,但也很容易“翻车”。下面是几个常见场景。
场景一: 崩溃之王
KVO的经典翻车操作是忘记移除观察者。这样会导致观察者释放后仍收到通知,最终直接野指针崩溃。
// 手滑少写一句 removeObserver,直接喜提崩溃
[object addObserver:self forKeyPath:@"value" options:NSKeyValueObservingOptionNew context:nil];
// 忘记解除,崩溃警告!
// [object removeObserver:self forKeyPath:@"value"];
场景二:神秘失踪的通知
如果直接修改实例变量,而不是通过setter,KVO就无法感知变化。此时它就像“什么都没看到”。
// KVO:我什么都没看到,别问我
_value = 100;
场景三:多线程迷惑行为
KVO通知可能在任意线程出发。开发者如果忘记切回主线程更新UI,界面就可能直接卡成PPT。
优缺点
优点
KVO可以实现对象之间的解耦。一个对象可以监听另一个对象的属性改变,并及时更新自己的状态。
此外,KVO 还可以实现对象的属性验证和数据过滤等功能。
缺点
- 需要手动移除观察者,容易导致内存泄漏
- 回调方法比较混乱,需要手动判断该
KeyPath - 不方便调试
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- iOS 调用 Lua:方法传递、返回值与数组字典映射说明
- 时间:2026-08-25
-
- iOS 临时通知怎么用:不弹授权框,也能先把通知发出去
- 时间:2026-08-25
-
- iOS 小组件配置梳理:App ID、Group ID 与描述文件怎么配
- 时间:2026-08-25
-
- iOS15震动强度调节上限详解与设置方法
- 时间:2026-08-24
-
- 不要被 ChatGPT 误导了,正确认识 iOS 中静态库和动态库
- 时间:2026-08-24
-
- Safari接力功能详解:Mac与iOS跨设备无缝协同指南
- 时间:2026-08-23
-
- iOS 14.3键盘手写输入功能开启与使用教程
- 时间:2026-08-23
-
- OPPO手机助手电脑版能否连接苹果iPhone使用
- 时间:2026-08-23
精选合集
更多大家都在玩
热门话题
大家都在看
更多-
- 条形码怎样批量打印?标签批量打印如何设置变量?
- 时间:2026-11-02
-
- Affinity Photo手机版下载哪里有 Affinity Photo汉化版下载靠谱吗
- 时间:2026-11-02
-
- 亿赛通数据加密算法有哪些?亿赛通数据加密怎么设置
- 时间:2026-11-02
-
- 怎么用Guitar Pro写特殊调弦 如何将五线谱转化为吉他谱
- 时间:2026-11-02
-
- idm视频嗅探不出怎么办 idm嗅探功能怎么打开
- 时间:2026-11-02
-
- 剪映怎么给视频设置封面图
- 时间:2026-11-02
-
- PS怎么用色阶和曲线调色
- 时间:2026-11-02
-
- Word怎么批量对齐选择题的ABCD选项
- 时间:2026-11-02
