iOS NSUserDefaults:监测单个键的值变化

19

我有以下代码,旨在捕获特定键的NSUserDefaults值更改事件。

 [[NSUserDefaults standardUserDefaults] addObserver:self
                                    forKeyPath:SOME_NSSTRING_VARIABLE
                                       options:NSKeyValueObservingOptionNew
                                       context:NULL];

 - (void)observeValueForKeyPath:(NSString *) keyPath ofObject:(id) object change:(NSDictionary *) change context:(void *) context
{NSLog (@"Changed for key %@", keyPath); }
但是 observeValueForKeyPath 从未被调用。 我甚至尝试使用字符串替换 SOME_NSSTRING_VARIABLE,如 Observing value changes to an NSUserDefaults key 中所述,但这并没有帮助。
更新: 我正在从选项卡视图更改 NSUserDefaults。 监听更改的上述代码位于同一选项卡视图控制器的不同选项卡中。 如果我在监视更改的选项卡中(存在上述代码的选项卡)添加“:”,则会发生什么。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//   NSLog(@"viewillappear");
NSUserDefaults *FUDefaults = [NSUserDefaults standardUserDefaults];
NSLog(@"The username obtained is: %@", [FUDefaults objectForKey:SOME_NSSTRING_VARIABLE]);
}

已经正确获取了更新后的NSUserDefaults值,但observeValueForKeyPath从未被调用。


请发布您更改变量的代码。 - trapper
你的 viewDidLoad 里面有 [[NSUserDefaults standardUserDefaults] addObserver... 吗? - trapper
NSUserDefaults *FDefaults = [NSUserDefaults standardUserDefaults]; [FDefaults setObject:userName.text forKey:SOME_NSSTRING_VARIABLE]; [[NSUserDefaults standardUserDefaults] synchronize()]; - Sankar
是的,我只在viewDidLoad函数中使用了addObserver...。 - Sankar
在为同一个问题苦苦挣扎了整整一天之后:请确保 SOME_NSSTRING_VARIABLE 不包含任何点,因为 keyPath 不应该被命名空间化以进行 KVO。 - Yunus Nedim Mehel
4个回答

28

编辑:viewDidUnload现已被弃用,请改用deallocremoveObserver

这应该可以完美地工作,我刚刚在这里测试过。

- (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);
    }
}

你可以测试的内容。

  • 在 viewDidUnload 中设置断点,确保视图未消失(因为你正在从另一个视图控制器更改 SomeKey)。如果是这种情况,则可能将注册/注销代码移动到 init/dealloc 中,具体取决于你的 VC 如何工作。

  • 使用显式的 KeyPath,例如 @"SomeKey",而不是替换变量,如 SOME_NSSTRING_VARIABLE


我刚刚在模拟器中进行了完整的手机重置,并进行了构建清理。现在一切都正常工作了。感谢您的代码。它甚至可以与SOME_NSSTRING_VARIABLE一起使用。 - Sankar
2
viewDidUnload现已弃用,请改用dealloc来移除观察者。 - foOg
是的,现在情况已经发生了改变。 - trapper

10

Swift 3版本:

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")
}

2

Swift版本:

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")
}

2

Swift 5 版本:

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

提示:确保varkeyPath完全相同。

在使用观察者的地方,执行以下操作:

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()
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接