如何使用 bind(_:to:withKeyPath:options:) 保持两个属性同步?
How to keep two properties in sync using bind(_:to:withKeyPath:options:)?
我想让两个属性与 Cocoa 绑定保持同步。
在我的代码中,您可以看到我有两个 类:A
和 B
。我希望使 A
和 B
实例中的 message
值保持同步,以便其中一个的更改反映在另一个中。我正在尝试使用 NSKeyValueBindingCreation
非正式协议的 bind(_:to:withKeyPath:options:)
方法。我在 macOS 上使用 Swift 4.2。
import Cocoa
class A: NSObject {
@objc dynamic var message = ""
}
class B: NSObject {
@objc dynamic var message = ""
init(_ a: A) {
super.init()
self.bind(#keyPath(message), to: a, withKeyPath: \.message, options: nil) // compile error
}
}
我在调用绑定的行中遇到编译错误:cannot convert value of type 'String' to expected argument type 'NSBindingName'
。我得到了用 NSBindingName(rawValue: )
包装第一个参数的建议。应用后,我得到第三个参数的错误 type of expression is ambiguous without more context
。
我做错了什么?
我在操场上做了下面的例子。我使用了计数器 class 而不是 class A 和 B,因为它更具描述性和更容易理解。
import Cocoa
class Counter: NSObject {
// Number we want to bind
@objc dynamic var number: Int
override init() {
number = 0
super.init()
}
}
// Create two counters and bind the number of the second counter to the number of the first counter
let firstCounter = Counter()
let secondCounter = Counter()
// You can do this in the constructor. This is for illustration purposes.
firstCounter.bind(NSBindingName(rawValue: #keyPath(Counter.number)), to: secondCounter, withKeyPath: #keyPath(Counter.number), options: nil)
secondCounter.bind(NSBindingName(rawValue: #keyPath(Counter.number)), to: firstCounter, withKeyPath: #keyPath(Counter.number), options: nil)
secondCounter.number = 10
firstCounter.number // Outputs 10
secondCounter.number // Outputs 10
firstCounter.number = 60
firstCounter.number // Outputs 60
secondCounter.number // Outputs 60
通常绑定用于绑定接口和控制器之间、控制器对象之间或控制器对象和模型对象之间的值。它们旨在删除界面和数据模型之间的粘合代码。
如果你只想保持你自己的对象之间的值同步,我建议你改用Key-Value Observing。它有更多的好处,而且更容易。虽然 NSView 和 NSViewController 为您管理绑定,但您必须在释放自己的对象之前解除绑定,因为绑定对象保持对其他对象的弱引用。使用 KVO 可以更优雅地处理这个问题。
看看WWDC2017 Session 212 - What's New in Foundation。它展示了如何在现代应用程序中使用键路径和 KVO。
我想让两个属性与 Cocoa 绑定保持同步。
在我的代码中,您可以看到我有两个 类:A
和 B
。我希望使 A
和 B
实例中的 message
值保持同步,以便其中一个的更改反映在另一个中。我正在尝试使用 NSKeyValueBindingCreation
非正式协议的 bind(_:to:withKeyPath:options:)
方法。我在 macOS 上使用 Swift 4.2。
import Cocoa
class A: NSObject {
@objc dynamic var message = ""
}
class B: NSObject {
@objc dynamic var message = ""
init(_ a: A) {
super.init()
self.bind(#keyPath(message), to: a, withKeyPath: \.message, options: nil) // compile error
}
}
我在调用绑定的行中遇到编译错误:cannot convert value of type 'String' to expected argument type 'NSBindingName'
。我得到了用 NSBindingName(rawValue: )
包装第一个参数的建议。应用后,我得到第三个参数的错误 type of expression is ambiguous without more context
。
我做错了什么?
我在操场上做了下面的例子。我使用了计数器 class 而不是 class A 和 B,因为它更具描述性和更容易理解。
import Cocoa
class Counter: NSObject {
// Number we want to bind
@objc dynamic var number: Int
override init() {
number = 0
super.init()
}
}
// Create two counters and bind the number of the second counter to the number of the first counter
let firstCounter = Counter()
let secondCounter = Counter()
// You can do this in the constructor. This is for illustration purposes.
firstCounter.bind(NSBindingName(rawValue: #keyPath(Counter.number)), to: secondCounter, withKeyPath: #keyPath(Counter.number), options: nil)
secondCounter.bind(NSBindingName(rawValue: #keyPath(Counter.number)), to: firstCounter, withKeyPath: #keyPath(Counter.number), options: nil)
secondCounter.number = 10
firstCounter.number // Outputs 10
secondCounter.number // Outputs 10
firstCounter.number = 60
firstCounter.number // Outputs 60
secondCounter.number // Outputs 60
通常绑定用于绑定接口和控制器之间、控制器对象之间或控制器对象和模型对象之间的值。它们旨在删除界面和数据模型之间的粘合代码。
如果你只想保持你自己的对象之间的值同步,我建议你改用Key-Value Observing。它有更多的好处,而且更容易。虽然 NSView 和 NSViewController 为您管理绑定,但您必须在释放自己的对象之前解除绑定,因为绑定对象保持对其他对象的弱引用。使用 KVO 可以更优雅地处理这个问题。
看看WWDC2017 Session 212 - What's New in Foundation。它展示了如何在现代应用程序中使用键路径和 KVO。