Objective-C 类的属性观察者:willSet 与 didSet 的使用场景与注意事项

在 Objective-C 中,属性观察主要通过 Key-Value Observing (KVO) 实现,但 Swift 的 willSet/didSet 概念可通过以下方式模拟:

一、实现原理
  1. willSet 等效实现
    在 setter 方法中赋值前执行自定义逻辑:

    - (void)setName:(NSString *)newName {
        // willSet 等价操作
        [self willChangeValueForKey:@"name"];
        _name = newName;  // 实际赋值
        // didSet 等价操作
        [self didChangeValueForKey:@"name"];
    }
    

  2. didSet 等效实现
    didChangeValueForKey: 后添加逻辑:

    [self didChangeValueForKey:@"name"];
    // didSet 区域
    [self logNameChange]; // 自定义操作
    

二、核心使用场景
  1. 数据验证(willSet 场景)
    赋值前检查有效性:

    - (void)setAge:(NSInteger)age {
        if (age < 0) { // 类 willSet 逻辑
            age = 0;   // 自动校正
        }
        _age = age;
    }
    

  2. 依赖更新(didSet 场景)
    值变化后触发关联操作:

    - (void)setTemperature:(CGFloat)temp {
        _temperature = temp;
        // didSet 逻辑
        [self updateThermostatDisplay]; // 更新UI
    }
    

  3. KVO 通知集成
    手动触发观察者通知:

    - (void)setBalance:(double)balance {
        [self willChangeValueForKey:@"balance"];
        _balance = balance;
        [self didChangeValueForKey:@"balance"]; // 触发KVO
    }
    

三、关键注意事项
  1. 内存管理
    在 setter 中避免循环引用:

    - (void)setDelegate:(id<CustomDelegate>)delegate {
        _delegate = delegate; // 使用 weak 修饰
    }
    

  2. 线程安全
    多线程环境下需加锁:

    - (void)setCounter:(NSInteger)count {
        @synchronized(self) {
            _counter = count;
        }
    }
    

  3. KVO 合规性

    • 重写 +automaticallyNotifiesObserversForKey: 禁用自动通知
    • 手动调用 willChange/didChange 确保通知时序正确
  4. 性能优化
    避免在 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 调用。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐