Skip to content

Instantly share code, notes, and snippets.

@krzyzanowskim
Last active July 18, 2022 11:19
Show Gist options
  • Save krzyzanowskim/c0567f830f18158ab88b9ad7f99c0bb0 to your computer and use it in GitHub Desktop.
Save krzyzanowskim/c0567f830f18158ab88b9ad7f99c0bb0 to your computer and use it in GitHub Desktop.
// Usage
@MainActor
final class AppSettings: ObservableObject {
static let standard = AppSettings()
@Published(preferenceKey: AppSettingsKey.editorHighlightSelectedLine)
var editorHighlightSelectedLine: Bool = true
}
enum AppSettingsKey: String {
case editorHighlightSelectedLine = "editor.HighlightSelectedLine"
}
import Foundation
import Combine
private var cancellables: Set<AnyCancellable> = []
extension Published {
init<Key>(wrappedValue defaultValue: Value, preferenceKey: Key, store: UserDefaults = .standard) where Key: RawRepresentable, Key.RawValue == String {
self.init(wrappedValue: defaultValue, preferenceKey: preferenceKey.rawValue, store: store)
}
init(wrappedValue defaultValue: Value, preferenceKey: String, store: UserDefaults = .standard) {
let initialValue = store.value(forKey: preferenceKey) as? Value ?? defaultValue
self.init(initialValue: initialValue)
projectedValue.sink { value in
if let value = value as? AnyOptional, !value.isNil {
store.setValue(value, forKey: preferenceKey)
} else if let value = value as? AnyOptional, value.isNil {
store.removeObject(forKey: preferenceKey)
} else {
store.setValue(value, forKey: preferenceKey)
}
}
.store(in: &cancellables)
}
}
// Since our property wrapper's Value type isn't optional, but
// can still contain nil values, we'll have to introduce this
// protocol to enable us to cast any assigned value into a type
// that we can compare against nil:
private protocol AnyOptional {
var isNil: Bool { get }
}
extension Optional: AnyOptional {
var isNil: Bool { self == nil }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment