Swift如何实现双向绑定?

How to implement two way binding with Swift?

如何使用 Swift 2.0 实现双向数据绑定?

假设我有以下型号 class(使用 couchbase lite):

@objc(Person)
class Person: NSObject{
    @NSManaged var firstName: NSString?
    @NSManaged var lastName: NSString?
}

我喜欢像这样将属性绑定到给定的 formItemDescriptor:

class FormItemDescriptor {
    var tag: String?
    var value: Any?
}

如何使用双向绑定将 FormItemDescriptor.value 属性 绑定到 Person.firstName 属性?

所以模型中的更改会出现在表单中,反之亦然?

Swift 不支持开箱即用的绑定,但您可以使用 ReactiveKit.

等框架实现它们

例如,当您声明一个 observable 属性 时,您可以将它绑定到另一个 observable 属性。

let numberA: Property<Int>
let numberB: Property<Int>

numberA.bindTo(numberB)

要进行双向,也只需在其他方向绑定即可:

numberB.bindTo(numberA)

现在,只要你改变其中任何一个,另一个也会改变。

不过你的例子有点难,因为你需要从 @NSManaged 属性中进行绑定,而这些属性是无法进行的 Observable。这不是不可能,但是要使 Person 的属性起作用,应该支持键值观察 (KVO)。

例如,给定一个 Person 对象和一个标签,您可以使用方法 rValueForKeyPath 从启用 KVO 的 属性 中获取一个 属性,然后将该可观察对象绑定到标签,像这样:

let person: Person
let nameLabel: UILabel

person.rValueForKeyPath("firstName").bindTo(nameLabel)

如果您有一个像您的 FormItemDescriptor 这样的中间对象,那么您必须使其属性可观察。

class FormItemDescriptor {
  var tag: Property<String?>
  var value: Property<Any?>
}

现在可以建立绑定了

let person: Person
let descriptor: FormItemDescriptor

person.rValueForKeyPath("firstName").bindTo(descriptor.value)

因为 firstName 不可观察,您不能在另一个方向进行绑定,因此每当 value 发生变化时您必须手动更新它。

descriptor.value.observeNext { value in
  person.firstName = value as? NSString
}

我们还必须转换为 NSString,因为 valueAny? 类型。不过你应该重新考虑一下,看看能不能把它做成更强的类型。

请注意,UIKit 绑定来自 ReactiveUIKit 框架。查看我们的 ReactiveKit 文档以获取更多信息。