Objective-C 类的属性观察者:willSet 与 didSet 的使用场景与注意事项
·
Objective-C 类的属性观察者:willSet 与 didSet 的使用场景与注意事项
在 Objective-C 中,属性观察主要通过 Key-Value Observing (KVO) 实现,但 Swift 的 willSet/didSet 概念可通过以下方式模拟:
一、实现原理
-
willSet 等效实现
在 setter 方法中赋值前执行自定义逻辑:- (void)setName:(NSString *)newName { // willSet 等价操作 [self willChangeValueForKey:@"name"]; _name = newName; // 实际赋值 // didSet 等价操作 [self didChangeValueForKey:@"name"]; } -
didSet 等效实现
在didChangeValueForKey:后添加逻辑:[self didChangeValueForKey:@"name"]; // didSet 区域 [self logNameChange]; // 自定义操作
二、核心使用场景
-
数据验证(willSet 场景)
赋值前检查有效性:- (void)setAge:(NSInteger)age { if (age < 0) { // 类 willSet 逻辑 age = 0; // 自动校正 } _age = age; } -
依赖更新(didSet 场景)
值变化后触发关联操作:- (void)setTemperature:(CGFloat)temp { _temperature = temp; // didSet 逻辑 [self updateThermostatDisplay]; // 更新UI } -
KVO 通知集成
手动触发观察者通知:- (void)setBalance:(double)balance { [self willChangeValueForKey:@"balance"]; _balance = balance; [self didChangeValueForKey:@"balance"]; // 触发KVO }
三、关键注意事项
-
内存管理
在 setter 中避免循环引用:- (void)setDelegate:(id<CustomDelegate>)delegate { _delegate = delegate; // 使用 weak 修饰 } -
线程安全
多线程环境下需加锁:- (void)setCounter:(NSInteger)count { @synchronized(self) { _counter = count; } } -
KVO 合规性
- 重写
+automaticallyNotifiesObserversForKey:禁用自动通知 - 手动调用
willChange/didChange确保通知时序正确
- 重写
-
性能优化
避免在 setter 中执行耗时操作:- (void)setImageData:(NSData *)data { _imageData = data; // 将耗时操作异步化 dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self processImage]; }); }
四、与 Swift 的差异对比
| 特性 | Objective-C 实现 | Swift 原生 |
|---|---|---|
| 触发时机 | 手动在 setter 中控制 | 编译器自动生成 |
| KVO 集成 | 需显式调用 willChange/didChange |
自动触发 KVO |
| 线程安全 | 需开发者手动实现 | 无内置线程保护 |
最佳实践:优先使用 KVO 观察外部对象属性,对自身属性采用 setter 自定义逻辑。在需要精细控制通知时序的场景(如数据库事务)中,手动管理
willChange/didChange调用。
更多推荐
所有评论(0)