【问题标题】:NSUserDefaults setObject crashing in ThreadNSUserDefaults setObject 在线程中崩溃
【发布时间】:2015-09-29 18:53:39
【问题描述】:

我正在后台做一些事情。我也尝试将对象写入标准用户默认值。 从 iOS 9 开始,它就崩溃了。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

// calling some methods in the background
// also save a value to the user defaults
NSDate *aDate = [NSDate date];
[[NSUserDefaults standardUserDefaults] setObject:aDate forKey:@"date"]; // <-- crash: EXC_BAD_ACCESS

});

我找不到问题。 aDate 不为零。我也尝试在主线程(从后台线程)上执行 setObject:,但结果相同。

崩溃是零星的! 我做错了什么?

这是堆栈跟踪:

崩溃:com.apple.root.background-qos EXC_BAD_ACCESS KERN_INVALID_ADDRESS 在 0x0000000000000010

线程:崩溃:com.apple.root.background-qos 0 libobjc.A.dylib
0x0000000199b0dbd0 objc_msgSend + 16 1 基础
0x0000000185ea1eb4 -[NSObject(NSKeyValueObserverNotification) willChangeValueForKey:] + 324 2 核心基础
0x0000000185090994 _CFPreferencesSetValueWithContainer + 168 3 基础 0x0000000185eb9138 -[NSUserDefaults(NSUserDefaults) setObject:forKey:] + 56 4 AIR 0x00000001000f201c -[ServerSyncAgent syncUnsyncedEntities] (ServerSyncAgent.m:212) 5 libdispatch.dylib
0x000000019a2e97b0 _dispatch_call_block_and_release + 24 6 libdispatch.dylib 0x000000019a2e9770 _dispatch_client_callout + 16 7 libdispatch.dylib 0x000000019a2f7bb0 _dispatch_root_queue_drain + 2140 8 libdispatch.dylib 0x000000019a2f734c _dispatch_worker_thread3 + 112 9 libsystem_pthread.dylib 0x000000019a4fd478 _pthread_wqthread + 1092

【问题讨论】:

  • 你是不是在同一条线上崩溃了?我认为坠机是从其他地方发生的。我已经使用了上面的代码,没有遇到任何崩溃。
  • 你可以尝试用相同的键插入字符串吗?
  • 我在其他方法中也遇到了崩溃,我使用 NSUserDefaults setObject:崩溃总是在 setObject 行中:
  • @Matt 发布完整的堆栈跟踪。显示更多代码。
  • @Nikolai 刚刚添加了堆栈跟踪。如果我在代码中取消注释该行,它将再次崩溃,其中 NSUserDefaults setObject: 被调用。

标签: ios crash nsuserdefaults ios9


【解决方案1】:

来自Apple's documentation

NSUserDefaults 类是线程安全的。

发布的代码很好。你的错误在别处。

编辑:堆栈指出错误的来源:

您(或某些第 3 方库)在您的代码中的其他位置向[NSUserDefaults standardUserDefaults] 添加了一个 KVO 观察者。然而,NSUserDefaults 不符合 KVO,因此您无法添加观察者。

如果需要对用户默认设置的更改做出反应,您必须使用NSNotificationCenter 并注册NSUserDefaultsDidChangeNotification

第 2 次编辑: 不确定何时更改,但在现代 iOS 和 macOS 中,NSUserDefaults 是可观察到的键值对。上面链接的相同文档现在清楚地指出:

您可以使用键值观察为感兴趣的特定键注册观察者,以便在本地默认数据库的所有更新时收到通知。更多详情,请参阅 Key-Value Observing 编程指南。

【讨论】:

  • 我知道它是线程安全的。但是只有当我在其他方法中调用 NSUserDefaults 时才会发生崩溃。
  • @Matt 正如我所说,您提供的代码和信息没有问题。您遇到的崩溃来自代码中的另一个位置。如果没有更多信息,我们将无法为您提供帮助。
  • 真的很奇怪。我没有找到任何遵守 [NSUserDefaults standardUserDefaults] 的代码。我还删除了所有库。但它只出现在后台线程中。如果我在主线程上调用它,它可以工作。我可以尝试什么来发现问题? NSZombieEnabled 没有帮助,因为是我启用它,Crash 没有出现。
  • @Matt 在-[NSObject addObserver:forKeyPath:options:context:] 中设置符号断点,添加条件(BOOL)[$arg1 isKindOfClass:[NSUserDefaults class]] 并运行您的应用程序。当调试器停止时,它会将您指向有问题的代码。
  • 非常感谢!有一个观察者我没有找到。它应该只用于 Mac 库,但也用于 iOS。
猜你喜欢
  • 1970-01-01
  • 2012-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多