我找到了一种方法来做到这一点,但它更像是一种 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
处于初始化过程中(因为尚未加载视图)