10

我今天遇到了一个相当有趣的 exc_bad_access 崩溃。经过大量挖掘,我想出了以下信息(在模拟器中运行):

如果我只是运行代码,应用程序会在将数据加载到我的托管对象时随机崩溃。据我所知,当我将数据加载到托管对象时,它总是崩溃——而不是从我的 JSON dict 转换为数据到实际使用的对象的部分(从字符串和 NSNulls 到 ints/floats 和 nils)

当然,随机崩溃是邪恶的,所以我尝试在调试器中逐步完成该过程,但这并没有被证明是实际的——我正在处理很多对象,所以一个接一个地通过它们只是没有不工作。所以我决定添加一些 NSLogs 来跟踪这个过程并尝试以这种方式发现一个模式。

瞬间解决了崩溃问题。

过程中的任何地方只有一个 NSLog 防止了崩溃。

我最终追踪了堆栈跟踪并发现了实际问题:我在线程环境中访问托管对象,但不是从关联的 MOC 的 performBlockAndWait: 方法中访问。那时,崩溃对我来说非常明显——我很震惊我之前没有遇到更多问题。我敢打赌,在拥有 2-3 个对象的“小型”测试数据集和使用 NSLogs 在那里调试代码之间,错误在早些时候被非常有效地掩盖了......但问题仍然存在:

为什么 NSLog 可以防止应用程序崩溃?一段没有副作用的代码究竟如何改变应用程序其余部分的执行?这没有任何意义!

4

2 回答 2

13

令人惊讶的是,这是一种相当普遍的情况:我不止一次看到它在看似无关的地方启用登录会立即解决其他地方的时间问题。

这样做的原因是NSLog,就像许多其他输出函数一样,具有内部同步。某处有一个互斥锁,可以保护对 的内部缓冲区的访问NSLog,无论是在它NSLog本身还是在它使用的一个 I/O 库中。这种同步使调用者能够NSLog从多个线程中使用。正是这种同步改变了程序的时间,影响了竞争条件并最终解决了崩溃。

于 2013-04-10T18:53:58.637 回答
3

为什么 NSLog 可以防止应用程序崩溃?一段没有副作用的代码究竟如何改变应用程序其余部分的执行?这没有任何意义!

确实,这是有道理的。真的。

一个单一的NSLog力量将某些东西打印到您的控制台,它需要几秒钟的时间,并且在您对某个线程的处理完成和崩溃(可能是由于输入不可用)之间不再存在。

您的错误可能是由于异步调用。您的下一个过程在完成前一个过程之前开始。而您的下一个流程需要来自 previos 流程的数据。NSLog消耗一些时间。

于 2013-04-10T18:53:18.577 回答