Skip to content

Commit 6b4bfc2

Browse files
committed
Invalidating userDefaultsObservers in removeAllHandlers +++ Restart potentially existing observer +++ Update observer if UserDefaults being changed
1 parent e392a84 commit 6b4bfc2

File tree

2 files changed

+44
-9
lines changed

2 files changed

+44
-9
lines changed

Sources/KeyboardShortcuts/KeyboardShortcuts.swift

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,13 @@ public enum KeyboardShortcuts {
5555
- Important: Changing this property will not migrate existing shortcuts from the previous `UserDefaults` instance.
5656
- Note: All keyboard shortcut configurations are stored with the prefix `KeyboardShortcuts_` to avoid conflicts with other app data.
5757
*/
58-
public static var userDefaults = UserDefaults.standard
58+
public static var userDefaults = UserDefaults.standard {
59+
didSet {
60+
for observer in userDefaultsObservers {
61+
observer.update(suite: userDefaults)
62+
}
63+
}
64+
}
5965

6066
/**
6167
When `true`, event handlers will not be called for registered keyboard shortcuts.
@@ -198,6 +204,12 @@ public enum KeyboardShortcuts {
198204

199205
legacyKeyDownHandlers = [:]
200206
legacyKeyUpHandlers = [:]
207+
208+
// invalidate and remove all elements of userDefaultsObservers
209+
for observation in userDefaultsObservers {
210+
observation.invalidate()
211+
}
212+
userDefaultsObservers.removeAll()
201213
}
202214

203215
// TODO: Also add `.isEnabled(_ name: Name)`.
@@ -429,7 +441,7 @@ public enum KeyboardShortcuts {
429441
*/
430442
public static func onKeyDown(for name: Name, action: @escaping () -> Void) {
431443
legacyKeyDownHandlers[name, default: []].append(action)
432-
startObservingShortcut(for: name)
444+
startObservingShortcutIfNeeded(for: name)
433445
registerShortcutIfNeeded(for: name)
434446
}
435447

@@ -456,7 +468,7 @@ public enum KeyboardShortcuts {
456468
*/
457469
public static func onKeyUp(for name: Name, action: @escaping () -> Void) {
458470
legacyKeyUpHandlers[name, default: []].append(action)
459-
startObservingShortcut(for: name)
471+
startObservingShortcutIfNeeded(for: name)
460472
registerShortcutIfNeeded(for: name)
461473
}
462474

@@ -468,12 +480,28 @@ public enum KeyboardShortcuts {
468480

469481
/**
470482
Start observing UserDefaults changes for a specific shortcut name.
471-
Only starts observation if the shortcut is not already being observed.
483+
484+
This function manages the lifecycle of observations for keyboard shortcuts in the given suite (e.g. UserDefaults):
485+
- Checks if the shortcut is already being observed
486+
- If already observed, restarts the observation
487+
- If not observed, creates a new observation and adds it to the observers list
488+
489+
The observation handles changes to the shortcut configuration in the suite:
490+
- When the shortcut is removed (value becomes nil), unregisters the shortcut
491+
- When the shortcut is added or modified, registers the new shortcut
492+
493+
- Parameter name: The name of the shortcut to observe
472494
*/
473-
private static func startObservingShortcut(for name: Name) {
495+
private static func startObservingShortcutIfNeeded(for name: Name) {
474496
let key = userDefaultsKey(for: name)
475497

476-
let observation = UserDefaultsObservation(
498+
// check userDefaultsObservers to see if we are already observing this key
499+
if let observer = userDefaultsObservers.first(where: { $0.key == key }) {
500+
observer.start()
501+
return
502+
}
503+
504+
let observer = UserDefaultsObservation(
477505
suite: userDefaults,
478506
key: key
479507
) { value in
@@ -484,9 +512,9 @@ public enum KeyboardShortcuts {
484512
}
485513
}
486514

487-
observation.start()
515+
observer.start()
488516

489-
userDefaultsObservers.append(observation)
517+
userDefaultsObservers.append(observer)
490518
}
491519

492520
static func userDefaultsDidChange(name: Name) {

Sources/KeyboardShortcuts/Utilities.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,8 @@ extension Character {
563563
final class UserDefaultsObservation: NSObject {
564564
typealias Callback = (_ newKeyValue: String?) -> Void
565565

566-
private let key: String
566+
let key: String
567+
567568
static var observationContext = 0
568569
private weak var suite: UserDefaults?
569570
private var isObserving = false
@@ -615,6 +616,12 @@ final class UserDefaultsObservation: NSObject {
615616
}
616617
}
617618

619+
func update(suite new: UserDefaults) {
620+
invalidate()
621+
suite = new
622+
start()
623+
}
624+
618625
// swiftlint:disable:next block_based_kvo
619626
override func observeValue(
620627
forKeyPath keyPath: String?,

0 commit comments

Comments
 (0)