【问题标题】:iOS NSUserDefaults Watching the change of values for a single keyiOS NSUserDefaults 观察单个键值的变化
【发布时间】:2012-05-28 12:09:21
【问题描述】:

我有以下代码旨在捕获特定键的 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 永远不会被调用。我什至尝试用Observing value changes to an NSUserDefaults key 中提到的字符串替换 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。

【问题讨论】:

  • 请把你修改变量的代码贴出来
  • 我也认为你在viewDidLoad 里面有[[NSUserDefaults standardUserDefaults] addObserver...
  • NSUserDefaults *FDefaults = [NSUserDefaults standardUserDefaults]; [FDefaults setObject:userName.text forKey:SOME_NSSTRING_VARIABLE]; [[NSUserDefaults standardUserDefaults] 同步];
  • 是的,我只有在 viewDidLoad 函数里面有 addObserver...
  • 在同一问题上挣扎了一整天后:确保SOME_NSSTRING_VARIABLE 不包含任何点,因为不应为keyPath 命名空间以执行KVO。

标签: ios nsuserdefaults


【解决方案1】:

编辑: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 中设置一个断点并确保视图不会在您身上消失(因为您正在从另一个 viewController 更改 SomeKey)如果是这种情况,那么可能会移动您的注册/注销代码根据您的 VC 的工作方式进入 init/dealloc。

  • 使用像 @"SomeKey" 这样的显式 KeyPath 而不是像 SOME_NSSTRING_VARIABLE 这样的替换

【讨论】:

  • 我刚刚做了一个完整的手机重置(在模拟器中)并且也做了一个干净的构建。现在一切正常。感谢您的代码。它甚至适用于 SOME_NSSTRING_VARIABLE
  • viewDidUnload 现已弃用,使用 dealloc 代替 removeObserver
  • 是的,现在情况发生了变化
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2011-04-07
        • 2011-12-10
        • 1970-01-01
        • 1970-01-01
        • 2018-12-26
        • 1970-01-01
        • 1970-01-01
        • 2021-01-26
        • 1970-01-01
        相关资源
        最近更新 更多