绑定模型和视图:如何观察对象属性

问题描述 投票:2回答:1

我有一个结构类似于创建模型对象的表单的视图。我正在尝试将表单元素(UIControl)绑定到模型属性,以便在视图的相应模型属性更改时视图自动更新,而在控件更改时模型更新(双向绑定)。可以在视图不知道的情况下更改模型,因为可以将多个视图链接到一个相同的模型属性。

方法1:普通迅捷

我的问题如下:观察模型属性的更改,我尝试使用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
        }
    }
}

但是我模型的某些属性具有类型CustomEnumCustomClassBool?ClosedRange<Int>,为了观察起见,我必须将它们标记为@objc dynamic,这会产生错误:

Property cannot be marked @objc because its type cannot be represented in Objective-C

方法2:使用RxSwift 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)
}

方法3:使用RxSwift BehaviorRelays?

这是我第一次使用RxSwift,我知道我应该为模型使用BehaviorRelay,但是我不想更改所有模型属性,因为我的模型对象正在与其他框架一起使用。然后,我可以尝试实现桥接,以将模型属性转换为BehaviorRelay,但是我会遇到相同的问题:如何监听模型更改

[In this question,在不将所有模型属性重构为RxSwift的Variable(目前已弃用)的情况下,没有关于如何侦听属性更改的答案。

方法4:使用didSet Swift属性观察器?

普通Swift中的didSetwillSet属性观察者将允许侦听更改,但是这将需要使用这些观察者标记模型中的所有属性,由于我的模型对象很多,因此我觉得很不方便属性。如果有一种方法可以在运行时添加这些观察者,则可以解决我的问题。


我相信我要实现的目标是很普遍的,拥有一组修改模型对象的视图,但是我找不到一种将模型正确链接到视图的方法,因此当需要。

基本上,我正在寻找以下问题之一的答案:

  • 是否有我忽略的东西,有没有更好的方法来实现我想要的?
  • 如何克服“无法将属性标记为@objc”的问题?
  • 如何在不更改模型的情况下将模型对象桥接到BehaviorRelay?
  • 如何在运行时添加didSet观察者?
ios swift architecture rx-swift observer-pattern
1个回答
0
投票

您说过要做到这一点,以便“当视图的相应模型属性更改时,视图自动更新,而控件更改(双向绑定)时,模型也更新。”

© www.soinside.com 2019 - 2024. All rights reserved.