You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS UIKit MVC下Swift中一个模型如何通知另一个模型属性变更?

iOS模型间属性监听的常用实现方案

你提到的KVO和NotificationCenter并不局限于模型和控制器间通信,完全可以用于模型层内部的属性变更通知,针对你的场景,常用的实现方案如下:


1. 自定义闭包回调(最轻量化)

适合仅存在少量观察者的场景,无额外框架依赖,代码逻辑直观

class ModelA {
    static let shared = ModelA()
    // 若需要支持多个观察者,可改为数组存储多组回调
    var onFooUpdate: ((CustomObjectClassName) -> Void)?
    
    private(set) var foo: CustomObjectClassName {
        didSet {
            // foo变更时触发回调
            onFooUpdate?(foo)
        }
    }
}

class ModelB {
    private var bar: ModelC

    init() {
        self.bar = ModelC(ModelA.shared.foo)
        // 注册监听foo变更
        ModelA.shared.onFooUpdate = { [weak self] newFoo in
            guard let self = self else { return }
            self.bar = ModelC(newFoo)
        }
    }
}

2. KVO(键值观察)

适合需要兼容Objective-C代码、或者已有KVO使用规范的项目,要求被监听类继承NSObject

import Foundation
// ModelA需要继承NSObject,监听属性加@objc dynamic修饰
class ModelA: NSObject {
    static let shared = ModelA()
    @objc dynamic private(set) var foo: CustomObjectClassName
}

class ModelB {
    private var bar: ModelC
    // 存储KVO观测实例,否则会被提前释放导致监听失效
    private var fooObservation: NSKeyValueObservation?

    init() {
        self.bar = ModelC(ModelA.shared.foo)
        // 初始化KVO监听
        fooObservation = ModelA.shared.observe(\.foo, options: [.new]) { [weak self] _, change in
            guard let self = self, let newFoo = change.newValue else { return }
            self.bar = ModelC(newFoo)
        }
    }
}

3. NotificationCenter(通知中心)

适合存在多个不同类型对象需要监听foo变更的广播场景,耦合度更低

// 先全局定义通知名称
extension NSNotification.Name {
    static let modelAFooDidUpdate = NSNotification.Name("ModelAFooDidUpdateNotification")
}

class ModelA {
    static let shared = ModelA()
    private(set) var foo: CustomObjectClassName {
        didSet {
            // foo变更时广播通知
            NotificationCenter.default.post(name: .modelAFooDidUpdate, object: foo)
        }
    }
}

class ModelB {
    private var bar: ModelC

    init() {
        self.bar = ModelC(ModelA.shared.foo)
        // 注册通知监听
        NotificationCenter.default.addObserver(self, selector: #selector(handleFooUpdate(_:)), name: .modelAFooDidUpdate, object: nil)
    }

    @objc private func handleFooUpdate(_ notification: Notification) {
        guard let newFoo = notification.object as? CustomObjectClassName else { return }
        self.bar = ModelC(newFoo)
    }

    deinit {
        // 移除观察者,iOS9+系统会自动处理,但显式移除更稳妥
        NotificationCenter.default.removeObserver(self)
    }
}

4. Combine框架(iOS 13+支持)

适合现代Swift项目,响应式编程场景,代码更简洁易维护

import Combine

class ModelA {
    static let shared = ModelA()
    // 用@Published修饰属性,自动发布变更事件
    @Published private(set) var foo: CustomObjectClassName
}

class ModelB {
    private var bar: ModelC
    // 存储订阅实例,否则会被自动取消
    private var cancellable: AnyCancellable?

    init() {
        self.bar = ModelC(ModelA.shared.foo)
        // 订阅foo的变更事件
        cancellable = ModelA.shared.$foo
            .sink { [weak self] newFoo in
                guard let self = self else { return }
                self.bar = ModelC(newFoo)
            }
    }
}

方案选择建议

  • 若项目最低支持iOS13,优先选Combine,写法简洁安全,是苹果官方推荐的现代响应式方案
  • 若需要兼容旧版本,且只有1-2个观察者,选自定义闭包回调,无额外依赖性能最好
  • 若有多个不同模块的对象都需要监听foo变更,选NotificationCenter
  • 若项目本身有大量ObjC兼容代码,已经在用KVO规范,继续用KVO即可

内容的提问来源于stack exchange,提问作者XYZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 08:39:05