Skip to content

Instantly share code, notes, and snippets.

@ipedro
Last active July 1, 2024 13:49
Show Gist options
  • Save ipedro/9e7a20c0f240d1079a052b11fa81de33 to your computer and use it in GitHub Desktop.
Save ipedro/9e7a20c0f240d1079a052b11fa81de33 to your computer and use it in GitHub Desktop.
import SwiftUI
import Combine
typealias BindableObservableObject<T> = T where T: ObservableObject, T.ObjectWillChangePublisher == ObservableObjectPublisher
/// A type that exposes its writable properties as bindings.
extension ObservableObject where Self == BindableObservableObject<Self> {
/// A type that acts as a lens that exposes bindings to the
/// writable properties of this type.
typealias Bindings = ExposedBindings<Self>
/// A lens that exposes bindings to the writable properties
/// of this instance.
@MainActor
var bindings: Bindings {
Bindings(base: self)
}
}
/// A type that acts as a lens that exposes bindings to the
/// writable properties of a base object.
@dynamicMemberLookup
struct ExposedBindings<Base> where Base == BindableObservableObject<Base> {
/// The base object whose bindings are exposed.
fileprivate let base: Base
/// Returns a binding to the property at the given key path.
subscript<Value>(dynamicMember keyPath: ReferenceWritableKeyPath<Base, Value>) -> Binding<Value> {
Binding {
base[keyPath: keyPath]
} set: {
base[keyPath: keyPath] = $0
base.objectWillChange.send()
}
}
/// Returns a lens that exposes the bindings of the object
/// at the given key path.
subscript<T>(dynamicMember keyPath: KeyPath<Base, T>) -> ExposedBindings<T> where T == BindableObservableObject<T> {
ExposedBindings<T>(base: base[keyPath: keyPath])
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment