我有一个结构类似于创建模型对象的表单的视图。我正在尝试将表单元素(UIControl
)绑定到模型属性,以便在视图的相应模型属性更改时视图自动更新,而在控件更改时模型更新(双向绑定)。可以在视图不知道的情况下更改模型,因为可以将多个视图链接到一个相同的模型属性。
我的问题如下:观察模型属性的更改,我尝试使用KVO in Swift,特别是observe(_:changeHandler:)
方法。
class Binding<View: NSObject, Object: NSObject, ValueType> {
weak var object: Object?
weak var view: View?
var objectToViewObservation: NSKeyValueObservation?
var viewToObjectObservation: NSKeyValueObservation?
private var objectKeyPath: WritableKeyPath<Object, ValueType>
private var viewKeyPath: WritableKeyPath<View, ValueType>
init(betweenObject objectKeyPath: WritableKeyPath<Object, ValueType>,
andView viewKeyPath: WritableKeyPath<View, ValueType>) {
self.objectKeyPath = objectKeyPath
self.viewKeyPath = viewKeyPath
}
override func bind(_ object: Object, with view: View) {
super.bind(object, with: view)
self.object = object
self.view = view
// initial value from object to view
self.view![keyPath: viewKeyPath] = self.object![keyPath: objectKeyPath]
// object --> view
objectToViewObservation = object.observe(objectKeyPath) { _, change in
guard var view = self.view else {
// view doesn't exist anymore
self.objectToViewObservation = nil
return
}
guard let value = change.newValue else { return }
view[keyPath: self.viewKeyPath] = value
}
// view --> object
viewToObjectObservation = view.observe(viewKeyPath) { _, change in
guard var object = self.object else {
// object doesn't exist anymore
self.viewToObjectObservation = nil
return
}
guard let value = change.newValue else { return }
object[keyPath: self.objectKeyPath] = value
}
}
}
但是我模型的某些属性具有类型CustomEnum
,CustomClass
,Bool?
和ClosedRange<Int>
,为了观察起见,我必须将它们标记为@objc dynamic
,这会产生错误:
Property cannot be marked @objc because its type cannot be represented in Objective-C
rx.observe
我转向RxSwift和rx.observe
方法,认为我可以解决此问题,但是发生了同样的事情(这次是在运行时)。
// In some generic bridge class between the view and the model
func bind(to object: SomeObjectType) {
object.rx
.observe(SomeType.self, "someProperty")
.flatMap { Observable.from(optional: $0) }
.bind(to: self.controlProperty)
.disposed(by: disposeBag)
}
这是我第一次使用RxSwift,我知道我应该为模型使用BehaviorRelay,但是我不想更改所有模型属性,因为我的模型对象正在与其他框架一起使用。然后,我可以尝试实现桥接,以将模型属性转换为BehaviorRelay,但是我会遇到相同的问题:如何监听模型更改。
[In this question,在不将所有模型属性重构为RxSwift的Variable
(目前已弃用)的情况下,没有关于如何侦听属性更改的答案。
didSet
Swift属性观察器?普通Swift中的didSet
和willSet
属性观察者将允许侦听更改,但是这将需要使用这些观察者标记模型中的所有属性,由于我的模型对象很多,因此我觉得很不方便属性。如果有一种方法可以在运行时添加这些观察者,则可以解决我的问题。
我相信我要实现的目标是很普遍的,拥有一组修改模型对象的视图,但是我找不到一种将模型正确链接到视图的方法,因此当需要。
基本上,我正在寻找以下问题之一的答案:
didSet
观察者?您说过要做到这一点,以便“当视图的相应模型属性更改时,视图自动更新,而控件更改(双向绑定)时,模型也更新。”