Skip to content

Instantly share code, notes, and snippets.

@rydermackay
Last active June 25, 2021 13:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rydermackay/0facd634934cd5600d29f7bc2b6a966a to your computer and use it in GitHub Desktop.
Save rydermackay/0facd634934cd5600d29f7bc2b6a966a to your computer and use it in GitHub Desktop.
Reimplementing @invalidating
import UIKit
struct InvalidationOptions: OptionSet {
static let constraints = InvalidationOptions(rawValue: 1)
static let layout = InvalidationOptions(rawValue: 1 << 1)
static let display = InvalidationOptions(rawValue: 1 << 2)
let rawValue: Int8
}
@propertyWrapper
struct MyCoolInvalidating<Value: Equatable> {
static subscript<EnclosingSelf: UIView> (
_enclosingInstance instance: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Self>
) -> Value {
get { instance[keyPath: storageKeyPath].storage }
set {
let oldValue = instance[keyPath: storageKeyPath].storage
instance[keyPath: storageKeyPath].storage = newValue
guard oldValue != newValue else { return }
let options = instance[keyPath: storageKeyPath].options
if options.contains(.constraints) {
instance.setNeedsUpdateConstraints()
}
if options.contains(.layout) {
instance.setNeedsLayout()
}
if options.contains(.display) {
instance.setNeedsDisplay()
}
}
}
@available(*, unavailable, message: "This property wrapper can only be applied to classes")
var wrappedValue: Value {
get { fatalError() }
set { fatalError() }
}
private var storage: Value
private var options: InvalidationOptions
init(wrappedValue: Value, _ options: InvalidationOptions) {
storage = wrappedValue
self.options = options
}
}
class MyCoolView: UIView {
@MyCoolInvalidating(.display)
var color: UIColor = .red
override func draw(_ rect: CGRect) {
color.setFill()
UIRectFill(rect)
}
override func didMoveToWindow() {
super.didMoveToWindow()
let tap = UITapGestureRecognizer(target: self, action: #selector(tap(_:)))
addGestureRecognizer(tap)
}
@IBAction private func tap(_ sender: Any) {
color = UIColor(hue: CGFloat.random(in: 0...1), saturation: 1, brightness: 1, alpha: 1)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment