使用 KVO 和延迟选择器观察 NSUserDefaults 时的 iOS exc_bad_access

Posted

技术标签:

【中文标题】使用 KVO 和延迟选择器观察 NSUserDefaults 时的 iOS exc_bad_access【英文标题】:iOS exc_bad_access when observing NSUserDefaults with KVO and delayedSelector 【发布时间】:2014-01-02 19:55:46 【问题描述】:

我遇到了一个奇怪的错误,想检查一下我是否正确地使用我的 Key 值来观察对 NSUserDefaults 的更改。

我在我的应用程序的两个地方使用了这段代码,没有出现问题,然后我添加了第三个控制器来观察“goldCount”和“energyCount”的值。现在,当我设置初始值时,应用程序因 exc_bad_access 而崩溃。在它的父视图使用performSelectorAfterDelay 出现 2 秒后,我将此控制器添加到视图中。

就在显示游戏画面之前,我设置了以下属性:

//crash on this line 
[[NSUserDefaults standardUserDefaults] setInteger:200 forKey: goldCount]; 

[[NSUserDefaults standardUserDefaults] setInteger:150 forKey: energyCount];

在 3 个不同的视图控制器中,我在 viewDidLoad 中有这段代码:

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults addObserver:self
           forKeyPath:@"goldCount"
              options:NSKeyValueObservingOptionNew
              context:NULL];

[defaults addObserver:self
           forKeyPath:@"energyCount"
              options:NSKeyValueObservingOptionNew
              context:NULL];

self.goldLabel.text = [NSString stringWithFormat:@"%i",[[GameDataManager sharedInstance] currentGoldCount]];
self.energyLabel.text = [NSString stringWithFormat:@"%i",[[GameDataManager sharedInstance] currentEnergyCount]];

以下是该类更新其标签的方式:

// KVO handler
-(void)observeValueForKeyPath:(NSString *)aKeyPath ofObject:(id)anObject
                       change:(NSDictionary *)aChange context:(void *)aContext


    //aKeyPath gives us the name of a user default that has changed
    if([aKeyPath isEqualToString:@"goldCount"])
    
        //we are interested in the new value
        self.goldLabel.text = [NSString stringWithFormat:@"%i",[[aChange objectForKey:@"new"] intValue]];
    else if([aKeyPath isEqualToString:@"energyCount"])
    
        self.energyLabel.text = [NSString stringWithFormat:@"%i",[[aChange objectForKey:@"new"] intValue]];
    


添加调用后 [[NSUserDefaults standardUserDefaults] synchronize];我第二次遇到这个异常:

由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“( ): An -observeValueForKeyPath:ofObject:change:context: 消息已收到但未处理。 关键路径:goldCount 观察对象: 改变: 种类 = 1; 新 = 205; 上下文:0x0'

【问题讨论】:

第一行是goldCount是什么?不应该是@"goldCount" 吗? - 观察者是否被正确移除(例如在dealloc 中? 静态 NSString* goldCount = @"goldCount"; 发现问题 - 我留下了第二次实例化同一个控制器的旧代码。正是这个解除分配的实例收到了通知并导致了异常。更多信息在这里:***.com/questions/4120539/… @AlexStone 请理解,即使您的代码目前看起来可以工作,它也有可能在任何给定时间破坏它的问题。 【参考方案1】:

NSUserDefaults 未记录为与 KVO 兼容,因此无法通过它们的键来观察默认值。这可能是崩溃的原因,但如果没有堆栈跟踪,则无法判断。

您可以注册一个通知,宣布更改默认系统:NSUserDefaultsDidChangeNotification

【讨论】:

以上是关于使用 KVO 和延迟选择器观察 NSUserDefaults 时的 iOS exc_bad_access的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C 观察者模式--KVO和NSNotificationCenter的使用

KVO-理解与简单使用

KVO

KVO的使用

UI进阶 KVO

Swift 中是不是提供键值观察 (KVO)?