swift用户默认值观察所有关键路径

pbpqsu0x  于 2022-11-28  发布在  Swift
关注(0)|答案(1)|浏览(151)

我知道如何观察用户默认值的变化-即

UserDefaults.standard.addObserver( this, forKeyPath: "Bob" context: nil )

但我有一堆设置,我想对所有设置都做同样的事情,而不想在添加新设置时添加代码。如何订阅 * 所有 * 密钥路径?
例如:

UserDefaults.standard.addObserver( this, forKeyPath: "*" context: nil )
rdrgkggo

rdrgkggo1#

所以在@HangarRash提到didChangeNotification之后a-我最终得到了这个,它实际上完全可以工作--但是代码量很大--一定有更好的方法:

import Foundation
import Combine

//
// we want to subscribe to any changes in user defaults
//
public class UserDefaultWatcher : NSObject
{
    //
    // the particular suite of defaults we are watching
    //
    private let _source : UserDefaults
    
    //
    // all key paths that we have asked to observe
    //
    private var _knownSubscriptions = Set<String>()
    
    //
    // we throw all work across to this queue to prevent any threading issues
    //
    private let _queue = DispatchQueue(label: "user_default_watcher")
    
    //
    // our subscription to userDefaults.didChangenotification
    //
    private var _subscription : AnyCancellable? = nil
    
    //
    // we expose this as the result
    //
    private let _subject =  PassthroughSubject<(String,Any), Error>()
    
    //
    // the instance of this
    //
    public static let instance = UserDefaultWatcher( source: UserDefaults.standard )
    
    //
    // something we can subscribe to
    //
    public var values : any Subject<(String,Any),Error> {
        return _subject
    }
    
    //
    // this is what it's all about... here we send out the change to anyone listening
    //
    private func sendChange( key: String, value: Any )
    {
        _subject.send((key, value))
    }
    
    //
    // setup observers for everything - this is called a lot, so we only want to setup observers for
    // new variables
    //
    private func setupObservers( sendEvents : Bool)
    {
        for (key, value) in _source.dictionaryRepresentation()
        {
            if (key.starts(with: "NS") || key.starts(with: "Apple"))
            {
                continue
            }
            if !_knownSubscriptions.contains(key)
            {
                _knownSubscriptions.insert(key)
                UserDefaults.standard.addObserver(self, forKeyPath: key, context: nil)
                if sendEvents
                {
                    sendChange( key: key, value: value )
                }
            }
       }
    }
    
    //
    // when this is initialized, we just subscribe to all the variables in userdefauls
    //
    public init( source : UserDefaults)
    {
        _source = source
        super.init()
        self._subscription = NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification).sink
        {
            notification in
            self._queue.async
            {
                self.setupObservers(sendEvents: true)
            }
        }
        _queue.async
        {
            self.setupObservers( sendEvents: false )
        }
    }
    
    //
    // when we get an event saying one of the keys has changed, we just send it off as a change
    //
    override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
    {
        _queue.async
        {
            if let key = keyPath, let value = self._source.dictionaryRepresentation()[key]
            {
                self.sendChange(key: key, value: value )
            }
        }
    }
    
    //
    // clean up all the subscriptions
    //
    deinit
    {
        _subscription?.cancel()
        for  keyPath in _knownSubscriptions
        {
            UserDefaults.standard.removeObserver(self, forKeyPath: keyPath)
        }
    }
}

所以我可以这样使用它:

UserDefaultWatcher.values.sink(...)

相关问题