Skip to content

Instantly share code, notes, and snippets.

@IanKeen
Last active February 28, 2023 21:20
Show Gist options
  • Save IanKeen/6c28a0fbd9e51ed108444b0235b3af16 to your computer and use it in GitHub Desktop.
Save IanKeen/6c28a0fbd9e51ed108444b0235b3af16 to your computer and use it in GitHub Desktop.
PropertyWrapper: Automatically redraw UIViews when a value changes
@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 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