0

我已经为 UIView、UILabel 等 UI 组件的主题创建了自己的属性包装器。

 class MyUIViewController: UIViewController {
    @Theme private override var view: UIView! // it doesnt work!!!
    @Theme private var myCustomView: UIView! // it works!!
 }

在这种情况下,我会得到一个编译错误“不能用存储的属性'view'覆盖”

我知道视图是 UIViewController 的一个属性。您知道是否有任何可能的方法将属性包装器应用于存储的(超类)属性?任何建议将不胜感激:) 非常感谢!

4

1 回答 1

0

我找到了一种方法来做到这一点,但它更像是一种 hack而不是一个好的实现(所以我不推荐它),而且我还没有完全测试它(因为它真的在 UIViewController 视图加载机制上,这可能会导致一些未定义的行为)。

也就是说,在属性包装器文档中,您可以找到解释属性包装器如何工作的“翻译示例”。

@Lazy var foo = 1738

// translates to:

private var _foo: Lazy<Int> = Lazy<Int>(wrappedValue: 1738)
var foo: Int {
  get { return _foo.wrappedValue }
  set { _foo.wrappedValue = newValue }
}

所以我们可以模仿这个来手动包装一个超类属性。

请注意,在view属性上执行此操作有点特殊,因为在视图控制器初始化期间未加载视图,但更像是一个惰性 var。

@propertyWrapper
struct Theme<WrappedValue: UIView> {
    var wrappedValue: WrappedValue?
}

class Controller: UIViewController {
    override func loadView() {
        super.loadView()
        _view.wrappedValue = view
    }

    private var _view: Theme<UIView> = .init()
    override var view: UIView! {
        get {
            if _view.wrappedValue == nil {
                // This is a trick I would not recommend using, but basically this line
                // forces the UIViewController to load its view and trigger the
                // loadView() method.
                _ = super.view
            }
            return _view.wrappedValue
        }
        set {
            _view.wrappedValue = newValue
        }
    }
}

我将属性包装器中的包装值设为可选,因为该view属性nil处于初始化过程中(因为尚未加载视图)

于 2020-04-22T09:42:36.473 回答