Skip to content

Instantly share code, notes, and snippets.

@lordzsolt
Last active April 1, 2023 16:49
Show Gist options
  • Save lordzsolt/cf96c5bc4619b2a09d32bce5a5254c27 to your computer and use it in GitHub Desktop.
Save lordzsolt/cf96c5bc4619b2a09d32bce5a5254c27 to your computer and use it in GitHub Desktop.
SwiftyUserDefaults Property wrapper that works with SwiftUI
@available(iOS 13.0, *)
@propertyWrapper
public final class PublishedUserDefault<T: DefaultsSerializable> where T.T == T {
public let key: DefaultsKey<T>
private var _value: T.T?
private var observation: DefaultsDisposable?
public init(keyPath: KeyPath<DefaultsKeys, DefaultsKey<T>>) {
self.key = Defaults.keyStore[keyPath: keyPath]
}
public static subscript<EnclosingType: ObservableObject>(
_enclosingInstance instance: EnclosingType,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingType, T>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingType, PublishedUserDefault>
) -> T {
get {
defer {
instance[keyPath: storageKeyPath].observation = Defaults.observe(instance[keyPath: storageKeyPath].key) { [weak instance] update in
guard let instance else { return }
let publisher = instance.objectWillChange
// This assumption is definitely not safe to make in
// production code, but it's fine for this demo purpose:
(publisher as! ObservableObjectPublisher).send()
instance[keyPath: storageKeyPath]._value = update.newValue
}
}
return instance[keyPath: storageKeyPath]._value ?? Defaults[key: instance[keyPath: storageKeyPath].key]
}
set {
let publisher = instance.objectWillChange
// This assumption is definitely not safe to make in
// production code, but it's fine for this demo purpose:
(publisher as! ObservableObjectPublisher).send()
instance[keyPath: storageKeyPath]._value = newValue
Defaults[key: instance[keyPath: storageKeyPath].key] = newValue
}
}
@available(*, unavailable,
message: "@Proxy can only be applied to classes"
)
public var wrappedValue: T {
get { fatalError() }
set { fatalError() }
}
deinit {
observation?.dispose()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment