本文通过一段简单的代码实现, 演示 Cocoa Binding 的用法.

Cocoa Binding 是苹果在 macOS 平台上推出的基于 KVC/KVO 实现的单向绑定工具, 可以方便地将模型属性绑定到 UI 上, 从而实现 UI “响应式”更新.

在网上到处都是介绍 StoryBoard 中建立绑定的例子, 这里就来看如何通过纯代码实现绑定.

  1. 初始代码如下所示(包含一个 NSTextField 用于展示数据, 一个 NSButton):

    swift
    class ViewController: NSViewController {
        private let btn = NSButton()
        private let label = NSTextField()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            btn.action = #selector(increaseValue)
        }
    
        override func loadView() {
            view = NSView(frame: NSRect(x: 0, y: 0, width: 300, height: 300))
        }
    
        @objc private func increaseValue() { 
            // TODO: 待实现
        }
    }
  2. 创建数据模型提供可供绑定的数据属性:

    swift
    class ViewModel: NSObject {
        @objc dynamic var currentValue = 1
    
        func update() { currentValue += 1 }
    }

    其中需要注意:

    1. 用于绑定的模型类必须继承自 NSObject.
    2. 被绑定的属性必须使用 @objc dynamic 修饰.
  3. 将模型放入控制器:

    swift
    class ViewController: NSViewController {
        // ...
    
        private let viewModel = ViewModel()
    
        // ...
    }
  4. 建立绑定:

    swift
    class ViewController: NSViewController {
        // ...
    
        override func viewDidLoad() {
            super.viewDidLoad()
            btn.action = #selector(increaseValue)
            label.bind(.value, to: viewModel, withKeyPath: "currentValue")
        }
    
        // ...
    }

    这个绑定的意思是: 将数据模型 viewModel 的可绑定属性 currentValue 绑定到 label 对象的 value 接口上. 其中第一个参数就是绑定的接口, 第二个参数是数据模型, 第三个参数是以字符串表示的 keyPath.

    关于特定 NSControl 的可绑定接口信息, 详见官方文档.

  5. 触发数据更新: 只需调用模型对象的 update 方法, 即可进行响应式 UI 更新:

    swift
    @objc private func increaseValue() { 
        viewModel.update() 
    }

完成绑定的建立.

后续

补充完整有关 TableView 等需要数组进行绑定的例子.