Last active
February 28, 2023 21:20
-
-
Save IanKeen/6c28a0fbd9e51ed108444b0235b3af16 to your computer and use it in GitHub Desktop.
PropertyWrapper: Automatically redraw UIViews when a value changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@propertyWrapper | |
struct Redraw<Value> { | |
var wrappedValue: Value | |
init(wrappedValue: Value) { | |
self.wrappedValue = wrappedValue | |
} | |
static subscript<Instance: UIView>( | |
_enclosingInstance instance: Instance, | |
wrapped wrappedKeyPath: ReferenceWritableKeyPath<Instance, Value>, | |
storage storageKeyPath: ReferenceWritableKeyPath<Instance, Self> | |
) -> Value { | |
get { instance[keyPath: storageKeyPath].wrappedValue } | |
set { | |
instance[keyPath: storageKeyPath].wrappedValue = newValue | |
instance.setNeedsDisplay() | |
} | |
} | |
} | |
// Usage | |
class MyView: UIView { | |
@Redraw var font = UIFont.systemFont(ofSize: 10) | |
} | |
let instance = MyView() | |
print(instance.font) | |
instance.font = .boldSystemFont(ofSize: 40) | |
print(instance.font) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This one tracks changes to the value and attempts a refresh with any mutations | |
@propertyWrapper | |
struct Redraw<Value: UIView> { | |
@dynamicMemberLookup | |
struct Box { | |
private var value: Value | |
init(_ value: Value) { | |
self.value = value | |
} | |
subscript<T>(dynamicMember keyPath: ReferenceWritableKeyPath<Value, T>) -> T { | |
get { value[keyPath: keyPath] } | |
set { | |
value[keyPath: keyPath] = newValue | |
value.superview?.setNeedsDisplay() | |
} | |
} | |
} | |
var wrappedValue: Box | |
init(wrappedValue: Value) { | |
self.wrappedValue = .init(wrappedValue) | |
} | |
init(wrappedValue: Box) { | |
fatalError("Please create with an instance of `\(type(of: Value.self))") | |
} | |
} | |
// Usage | |
class MyView: UIView { | |
@Redraw var label = UILabel() | |
} | |
let instance = MyView() | |
instance.label.text = "Foo" // this will trigger a refresh |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment