時々必要になる、「特定のプロパティが変わったら再レイアウトが必要なことをUIKitに伝える」という仕組み
一般的な方法として、次のような実装が挙げられます。
var myProperty: Int = 0 {
didSet {
setNeedsLayout()
}
}
また、レイアウトに限らず、setNeedsDisplayを呼ぶ必要があるケースも多いと思います。
これをPropertyWrapperを使って短くかけないか、というのが今回のテーマ
作ってみたのが次のコード
class MyView: UIView {
@ViewState var count: Int = 0
override func setNeedsLayout() {
print("SetNeedsLayout")
super.setNeedsLayout()
}
}
@ViewState
で定義したプロパティは変更されるとsetNeedsLayoutが呼び出されます。
実現方法として、メインはPropertyWrapperの利用ですが、その中でも
Referencing the enclosing 'self' in a wrapper type という機能を利用したものになります。
@propertyWrapper
public struct ViewState<T> {
public static subscript<EnclosingSelf: UIView, TargetValue>(
_enclosingInstance instance: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, TargetValue>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
) -> T {
get {
let value = instance[keyPath: storageKeyPath].wrappedValue
return value
}
set {
instance[keyPath: storageKeyPath].wrappedValue = newValue
instance.setNeedsLayout()
}
}
public var wrappedValue: T
public var projectedValue: ViewState<T> {
self
}
public init(wrappedValue: T) {
self.wrappedValue = wrappedValue
}
}