Created
February 4, 2024 10:20
-
-
Save shaundon/15935d4e3c3d6ae8aaf6674ab112528f to your computer and use it in GitHub Desktop.
Proof of concept of UserDefaults plus Zephyr, making use of notifications to update the UI when a value changes externally.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct ContentView: View { | |
@State private var preferences = PreferencesModel() | |
var body: some View { | |
VStack { | |
HStack { | |
Text("Value: ") | |
Text(preferences.theNumber.formatted()).bold() | |
} | |
Button(action: changeNumber) { | |
Text("Change number") | |
} | |
} | |
.padding() | |
} | |
func changeNumber() { | |
preferences.theNumber = Int.random(in: 1...100) | |
} | |
} | |
#Preview { | |
ContentView() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import Zephyr | |
@Observable | |
class PreferencesModel { | |
init() { | |
/// Watch for changes to UserDefaults. | |
/// This will fire when a value changes externally and Zephyr updates | |
/// UserDefaults in kind. | |
let observer = NotificationCenter.default.addObserver( | |
forName: UserDefaults.didChangeNotification, | |
object: nil, | |
queue: nil, | |
using: handleUpdatedUserDefaults | |
) | |
Zephyr.debugEnabled = true | |
Zephyr.sync(keys: UserPreferences.Keys.allKeyValues) | |
Zephyr.addKeysToBeMonitored(keys: UserPreferences.Keys.allKeyValues) | |
} | |
/// See what changed in UserDefaults and update our model in kind. | |
/// This means that when a value changes externally, the UI will update automatically. | |
private func handleUpdatedUserDefaults(from notification: Notification) { | |
guard let updatedUserDefaults = notification.object as? UserDefaults else { | |
return | |
} | |
let updatedNumber = updatedUserDefaults.integer(forKey: UserPreferences.Keys.theNumber.rawValue) | |
if updatedNumber != self.theNumber { | |
self.theNumber = updatedNumber | |
} | |
} | |
/// Observable var directly linked to UserDefaults. | |
/// When it's set from a view (e.g. in ContentView), UserDefaults is automatically updated to match. | |
var theNumber = UserPreferences.theNumber { | |
didSet { UserPreferences.theNumber = self.theNumber } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct UserPreferences { | |
/// Convenience enum for noting all the keys we store in UserDefaults. | |
enum Keys: String, CaseIterable { | |
case theNumber | |
static var allKeyValues: [String] { | |
Self.allCases.map { $0.rawValue } | |
} | |
} | |
/// Standard value stored in UserDefaults. | |
static var theNumber: Int { | |
get { return UserDefaults.standard.integer(forKey: Keys.theNumber.rawValue) } | |
set { UserDefaults.standard.set(newValue, forKey: Keys.theNumber.rawValue) } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment