我们已经很习惯使用第三方的库来调用UserDefaults了。但是有时我们也需要只使用苹果官方的框架来实现相同的功能。
- 创建Key
- 注册iCloud的变化
- 更新userdefaults
- 注册Key的变化
- 更新iCloud
创建Key
extension UserDefaults {
static let text = "text"
}
注册iCloud的变化
class AppDelegate: NSObject, NSApplicationDelegate {
@AppStorage(UserDefaults.text) private var text: String = "Hello, Zhao!"
func applicationDidFinishLaunching(_ notification: Notification) {
registerKeyValueSyncing()
}
}
extension AppDelegate {
private func registerKeyValueSyncing() {
NotificationCenter.default.addObserver(forName: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: NSUbiquitousKeyValueStore.default, queue: nil) { [self] notification in
guard let userInfo = notification.userInfo else { return }
guard let reasonForChange = userInfo[NSUbiquitousKeyValueStoreChangeReasonKey] as? Int else { return }
guard let keys = userInfo[NSUbiquitousKeyValueStoreChangedKeysKey] as? [String] else { return }
guard keys.contains(UserDefaults.text) else { return }
if reasonForChange == NSUbiquitousKeyValueStoreAccountChange {
text = "Hello, Zhao!"
return
}
if let newText = NSUbiquitousKeyValueStore.default.string(forKey: UserDefaults.text),
newText != text {
text = newText
print("update text to \(text)")
}
}
UserDefaults.standard.addObserver(self, forKeyPath: UserDefaults.text, options: [.new, .initial], context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let keyPath, keyPath == UserDefaults.text else { return }
if let change {
print("[debug] change is \(change)")
if let newText = change[.newKey] as? String {
NSUbiquitousKeyValueStore.default.set(newText, forKey: keyPath)
}
}
}
}
主程序
@main
struct KeyValueSyncingApp: App {
#if os(macOS)
@NSApplicationDelegateAdaptor private var appDelegate: AppDelegate
#else
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
#endif
var body: some Scene {
WindowGroup {
ContentView()
}
}
}