iOS NSUserDefaults Watching the change of values for a single key

后端 未结 4 470
花落未央
花落未央 2020-12-15 21:52

I have the following code aiming to catch the event of a NSUserDefaults value changing for a particular key.

 [[NSUserDefaults standardUserDefaults] addObse         


        
相关标签:
4条回答
  • 2020-12-15 22:05

    Swift Version:

    func setUserDefaultsListener(){
        NSUserDefaults.standardUserDefaults().addObserver(self, forKeyPath: "keyPath", options: NSKeyValueObservingOptions.New, context: nil)
    }
    
    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        if keyPath == "keyPath" {
            //Do something
        }
    }
    
    deinit {
        NSUserDefaults.standardUserDefaults().removeObserver(self, forKeyPath: "keyPath")
    }
    
    0 讨论(0)
  • 2020-12-15 22:17

    Swift 5 Version:

    extension UserDefaults {
        @objc dynamic var keyPath: Int {
            return integer(forKey: "keyPath")
        }
    }
    

    HINT: make sure the var has exactly the same as the keyPath

    and where you use the observer do:

    var observer: NSKeyValueObservation?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        observer = UserDefaults.standard.observe(\.keyPath, options: [.initial, .new], changeHandler: { (defaults, change) in
            //Do something
        })
    }
    
    deinit {
        observer?.invalidate()
    }
    
    0 讨论(0)
  • 2020-12-15 22:23

    Edit: viewDidUnload is now deprecated, use dealloc instead to removeObserver

    This should work perfectly, I have just tested here.

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        [[NSUserDefaults standardUserDefaults] addObserver:self
                                                forKeyPath:@"SomeKey"
                                                   options:NSKeyValueObservingOptionNew
                                                   context:NULL];
        // Testing...
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 
        [defaults setObject:@"test" forKey:@"SomeKey"];
        [defaults synchronize];
    }
    
    - (void)viewDidUnload
    {
        [super viewDidUnload];
    
        [[NSUserDefaults standardUserDefaults] removeObserver:self forKeyPath:@"SomeKey"];
    }
    
    - (void)observeValueForKeyPath:(NSString *) keyPath ofObject:(id) object change:(NSDictionary *) change context:(void *) context
    {
        if([keyPath isEqual:@"SomeKey"])
        {
           NSLog(@"SomeKey change: %@", change);
        }
    }
    

    Things you could test.

    • Put a break point in viewDidUnload and make sure the view isn't disappearing on you (since you are changing SomeKey from another viewController) If this is the case then maybe move your register/de-register code into init/dealloc depending on how your VC works.

    • Use explicit KeyPath like @"SomeKey" not a substitution like SOME_NSSTRING_VARIABLE

    0 讨论(0)
  • 2020-12-15 22:27

    Swift 3 Version:

    override func viewDidLoad() {
        super.viewDidLoad()
        UserDefaults.standard.addObserver(self, forKeyPath: "keyPath", options: .new, context: nil)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "keyPath" {
            //Do something
        }
    }
    
    deinit {
        UserDefaults.standard.removeObserver(self, forKeyPath: "keyPath")
    }
    
    0 讨论(0)
提交回复
热议问题