Skip to content

Instantly share code, notes, and snippets.

@shadowfacts
Created January 28, 2024 01:09
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 shadowfacts/408bcbfaf9ab8f29f89c4b4c79f0836a to your computer and use it in GitHub Desktop.
Save shadowfacts/408bcbfaf9ab8f29f89c4b4c79f0836a to your computer and use it in GitHub Desktop.
struct ContentView: View {
@State var model = Model()
var body: some View {
let _ = Self._printChanges()
VStack {
Text(model.test)
Text("\(model.otherThing)")
Button("Toggle") {
model.bool.toggle()
}
Button("Inc") {
model.otherThing += 1
}
}
.padding()
}
}
@Observable
class Model {
var bool = false
var otherThing = 1
@ObservationIgnored
@DependencyTracked(provider: { (self: Model) in
print("provider ran")
return "test \(self.bool)"
})
var test: String
}
@propertyWrapper
struct DependencyTracked<Enclosing: Observable, Value> {
let provider: (Enclosing) -> Value
@State var tracker: Tracker
init(provider: @escaping (Enclosing) -> Value) {
self.provider = provider
self._tracker = State(initialValue: Tracker())
}
@available(*, unavailable)
var wrappedValue: Value {
fatalError("unreachable")
}
static subscript(_enclosingInstance instance: Enclosing, wrapped wrappedKeyPath: KeyPath<Enclosing, Value>, storage storageKeyPath: ReferenceWritableKeyPath<Enclosing, Self>) -> Value {
let wrapper = instance[keyPath: storageKeyPath]
if wrapper.tracker.value == nil {
wrapper.update(instance: instance)
}
return wrapper.tracker.value
}
private func update(instance: Enclosing) {
tracker.value = withObservationTracking {
provider(instance)
} onChange: {
DispatchQueue.main.async {
update(instance: instance)
}
}
}
@Observable
final class Tracker {
var value: Value!
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment