Swift Debug EXC_BAD_ACCESS in AppDelegate

不少人在开发中都会遇到 EXC_BAD_ACCESS ,很遗憾,这一次 Xcode 不会给出任何详细的解决方案。

通常来说,这是由于内存错误造成的。简单来说就是你创建了对象 A,但在后来访问的时候,内存里 A 这块区域已经被系统挪做他用了,比如放了对象 B 在这里——你的 A 只剩下指针,实际内容已经不存在了。

这时就会出现类似这样的崩溃:

-[__NSCFType dismissAuxiliaryWindows]: unrecognized selector sent to instance 0x6000030010e0

由于实际对象已经变更,Swift 编译器却并不知道,结果自然就是一个“未知的 Selector”了。

尝试解决它

一开始,无知的我想要去找到这个“instance”到底是谁,于是我开始用这个方法打印程序里的对象:

var a = 1
print(Unmanaged.passUnretained(a).toOpaque())

嗯,后来我发现这是一个无止境的工作……但报错变得有意思了:

-[_TtGCs23_ContiguousArrayStorageSS_$ dismissAuxiliaryWindows]: unrecognized selector sent to instance 0x600003004240

这让我更加摸不着头脑。

再后来,干脆就没报错了,就是 EXC_BAD_ACCESS ,于是内存地址对比也就到此为止了……

正确的做法

总之,Xcode 还是有工具来处理这种情况的——虽然不一定是百发百中,但至少能增加一点排错的线索,我们到 Xcode 左上角选择 Edit Scheme,编辑当前程序的执行选项:

选择 Edit Scheme… 来编辑运行参数

在打开的页面选“Run”,选右侧“Diagnosis”选项卡,勾选下方的“Zombie Object”。

开启 Zombie Object 模式

Zombie Object 模式:僵尸模式,在这个模式下你的程序不会真的释放需要被释放的内存,即使对象 A 已经没有引用,它也会被保留在内存当中,这样就避免了系统将其他对象的内存写到同一位置,一旦 EXC_BAD_ACCESS 发生,Xcode 将能够发现程序原本想要访问的是哪个对象。

再次运行程序,触发崩溃,我们得到了新的报错:

*** -[NSSpellChecker dismissAuxiliaryWindows]: message sent to deallocated instance 0x600003010b40

显然,这次就明确多了,虽然不知为何,但这次的 EXC_BAD_ACCESS 是由于程序访问了一个 NSSpellChecker 对象导致的,这下就大大缩小了排错范围,运气好的话应该很快就能定位问题所在了。

参考文献

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章