Listless/Sync/KeyValueSyncBridge.swift (2040B)
1import Foundation
2
3final class KeyValueSyncBridge {
4 private let keys: Set<String>
5 private var isSyncing = false
6
7 init(keys: Set<String>) {
8 self.keys = keys
9 }
10
11 func start() {
12 let cloud = NSUbiquitousKeyValueStore.default
13 cloud.synchronize()
14
15 for key in keys {
16 if let cloudValue = cloud.object(forKey: key) {
17 isSyncing = true
18 UserDefaults.standard.set(cloudValue, forKey: key)
19 isSyncing = false
20 }
21 }
22
23 NotificationCenter.default.addObserver(
24 self,
25 selector: #selector(cloudDidChange),
26 name: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
27 object: cloud
28 )
29
30 NotificationCenter.default.addObserver(
31 self,
32 selector: #selector(defaultsDidChange),
33 name: UserDefaults.didChangeNotification,
34 object: nil
35 )
36 }
37
38 @objc private func cloudDidChange(_ notification: Notification) {
39 guard !isSyncing else { return }
40 guard let changedKeys = notification.userInfo?[NSUbiquitousKeyValueStoreChangedKeysKey] as? [String] else {
41 return
42 }
43 let cloud = NSUbiquitousKeyValueStore.default
44 isSyncing = true
45 for key in changedKeys where keys.contains(key) {
46 UserDefaults.standard.set(cloud.object(forKey: key), forKey: key)
47 }
48 isSyncing = false
49 }
50
51 @objc private func defaultsDidChange(_ notification: Notification) {
52 guard !isSyncing else { return }
53 let defaults = UserDefaults.standard
54 let cloud = NSUbiquitousKeyValueStore.default
55 isSyncing = true
56 for key in keys {
57 let localValue = defaults.object(forKey: key) as? NSObject
58 let cloudValue = cloud.object(forKey: key) as? NSObject
59 if localValue != cloudValue {
60 cloud.set(localValue, forKey: key)
61 }
62 }
63 isSyncing = false
64 }
65}