Swift 1.2 中的神秘崩溃 - 仅在发布版本中

Mysterious crashes in Swift 1.2 - in Release builds only

更新到 Xcode 6.3(测试版 1)和 Swift 1.2 后,我的所有应用程序都莫名其妙地崩溃了 仅在发布版本中 。在调试版本中更新我的 Swift 1.2 代码后,它们工作正常。调试器无法判断崩溃发生的 位置 ,也不清楚原因。一些崩溃是

malloc: *** error for object 0x7ff0c3824800: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug

其他的是"unrecognized selector",但是没有意义;选择器发送到的对象甚至不是我知道使用的对象。内存管理似乎出了点问题,一个对象被另一个对象替代了。

到底是什么原因造成的?调用堆栈中没有任何有用的东西(因此我什至不知道我的代码中发生崩溃的位置)并且当我单步执行我的代码时调试器的变量窗格中没有显示任何变量(所以我什至不能看看事物的价值),我怎么可能开始追踪它呢?

令人惊奇的是,我确实追踪到了这个,主要是通过删除大样本中的代码,直到我只剩下这个(它是一个视图控制器):

class LessonListController: UIViewController {
    var terms : [Term]
    // var terms : NSArray
    init(terms data:NSArray) {
        let arr = data.sortedArrayUsingDescriptors([NSSortDescriptor(key: "lessonSection", ascending: true)])
        self.terms = arr as! [Term]
        // self.terms = arr
        super.init(nibName:"LessonList", bundle:nil)
    }
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    @IBAction func doDismiss(sender: AnyObject) {
        self.dismissViewControllerAnimated(true, completion: nil)
    }
}

如果(在 Release 版本中)我们呈现这个视图控制器然后关闭它,我们会在关闭时崩溃 - 在 dealloc 中,这证明了我的理论,这是内存管理的问题。

隔离代码后,我可以尝试各种替代方案。很明显,问题出在 属性 var terms : [Term](因为 Swift 在 dealloc 中唯一做的就是释放这个数组)。正如您在我的 init 中所见,此 属性 的值是一个来自 Cocoa(通过 sortedArrayUsingDescriptors)并已转换为 Swift数组。通过反复试验,我发现:

  • 如果我们更改实现,使 属性 是一个 NSArray(请参阅注释掉的替代行),我们不会崩溃。

  • 或者,如果我们不排序(这样这个 NSArray 就不会来自 Cocoa),我们就不会崩溃。

  • 或者(等等),如果我们用self.terms = arr as NSArray as! [Term]替换self.terms = arr as! [Term],我们不会崩溃!

但是第三种选择 是一种解决方法 。我检查了我所有应用程序中的所有代码以寻找 as! [SomeType] 转换并将它们全部替换为 as NSArray as [SomeType],并且 我所有的崩溃都消失了!!

我的理论是 Swift 在优化的 Release 构建中的内存管理出了问题,只是在 NSArray 从 Cocoa 到达并为我们桥接的非常特殊的情况下[AnyObject] 在我们的代码可以获取它之前。这样的 NSArray 没有正确地过桥。但是通过强制转换为 NSArray 然后返回到特定的 [SomeType] Swift 数组,问题就解决了。

当然,我假设当 Apple 解决这个问题时,他们会修复它,然后我们就可以停止使用这个解决方法。但在那之前,我的应用程序再次 运行 在发布版本中。