如何监听UserDefaults所有键路径?新增设置无需额外代码
监听UserDefaults所有键值变化的解决方案
UserDefaults的KVO机制**不支持使用通配符***来监听所有键路径的变化,你提到的forKeyPath: "*"写法是无效的。要实现“监听所有设置项变化、新增设置无需额外代码”的需求,可以用以下两种可靠方案:
方案一:监听系统自带的通知
系统提供了UserDefaults.didChangeNotification通知,每当UserDefaults中任意键值发生变化时都会触发该通知,且能获取到具体变化的键列表。
示例代码
// 在初始化代码中添加通知观察者 NotificationCenter.default.addObserver( self, selector: #selector(handleUserDefaultsChange(_:)), name: UserDefaults.didChangeNotification, object: UserDefaults.standard ) // 处理通知的方法 @objc private func handleUserDefaultsChange(_ notification: Notification) { // 获取所有变化的键 guard let changedKeys = notification.userInfo?[UserDefaults.changedKeysKey] as? [String] else { return } // 对每个变化的键执行统一逻辑 for key in changedKeys { let newValue = UserDefaults.standard.value(forKey: key) // 这里替换成你的实际处理代码 print("设置项 \(key) 已更新为: \(newValue ?? "nil")") } } // 记得在对象销毁时移除观察者 deinit { NotificationCenter.default.removeObserver(self) }
优缺点
- 优点:无需自定义子类,系统原生支持,实现简单;新增设置项自动被监听,无需额外修改代码。
- 缺点:通知触发存在轻微延迟;如果多个键值同时修改,只会触发一次通知。
方案二:自定义UserDefaults子类
通过重写UserDefaults的设置方法,在每次修改值时主动触发自定义通知或回调,这种方式更灵活,能精准控制触发时机。
示例代码
class TrackedUserDefaults: UserDefaults { // 定义自定义通知名称 static let didChangeNotification = Notification.Name("TrackedUserDefaultsDidChange") // 重写基础set方法 override func set(_ value: Any?, forKey defaultName: String) { super.set(value, forKey: defaultName) postChangeNotification(key: defaultName, value: value) } // 重写其他类型的set方法,确保覆盖所有修改场景 override func set(_ value: Int, forKey defaultName: String) { super.set(value, forKey: defaultName) postChangeNotification(key: defaultName, value: value) } override func set(_ value: Bool, forKey defaultName: String) { super.set(value, forKey: defaultName) postChangeNotification(key: defaultName, value: value) } // 统一发送通知的方法 private func postChangeNotification(key: String, value: Any?) { NotificationCenter.default.post( name: Self.didChangeNotification, object: self, userInfo: ["key": key, "value": value] ) } } // 使用方式 let trackedDefaults = TrackedUserDefaults.standard // 添加观察者 NotificationCenter.default.addObserver( self, selector: #selector(handleTrackedDefaultsChange(_:)), name: TrackedUserDefaults.didChangeNotification, object: trackedDefaults ) // 处理通知 @objc private func handleTrackedDefaultsChange(_ notification: Notification) { guard let key = notification.userInfo?["key"] as? String, let value = notification.userInfo?["value"] else { return } // 你的统一处理逻辑 print("设置项 \(key) 已更新为: \(value)") } // 销毁时移除观察者 deinit { NotificationCenter.default.removeObserver(self) }
优缺点
- 优点:触发时机精准,可自定义通知携带的信息;能完全控制所有修改操作的监听。
- 缺点:需要确保所有设置操作都通过自定义子类执行,否则无法监听;需要重写多个set方法覆盖不同数据类型。
内容的提问来源于stack exchange,提问作者Darren Oakey
相关产品推荐
相关产品推荐

