17

我有以下代码旨在捕获特定键的 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 永远不会被调用。我什至尝试用观察 NSUserDefaults 键的值更改中提到的字符串替换 SOME_NSSTRING_VARIABLE ,但它没有帮助。

更新:我正在从 tabview 更改 NSUserDefaults。上面监控更改的代码在同一个 tabviewcontroller 的不同选项卡中。在我监视更改的选项卡(存在上述代码的选项卡)中,如果我添加:

- (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。

4

4 回答 4

28

编辑:viewDidUnload现在已弃用,dealloc改为使用removeObserver

这应该可以完美运行,我刚刚在这里测试过。

- (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从另一个 viewController 更改)如果是这种情况,那么可能会将您的注册/取消注册代码移动到 init/dealloc 中,具体取决于您的 VC作品。

  • 使用显式 KeyPath@"SomeKey"而不是替代SOME_NSSTRING_VARIABLE

于 2012-05-28T12:38:46.800 回答
10

斯威夫特 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")
}
于 2017-04-22T14:18:02.213 回答
2

斯威夫特版本:

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")
}
于 2015-10-28T17:31:05.760 回答
2

斯威夫特 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()
}
于 2019-09-26T22:07:30.063 回答