使用弱变量上的可选链接调用方法会导致EXC_BAD_ACCESS

时间:2014-06-11 23:44:23

标签: swift weak-references

更新:这已在Xcode 6 beta 6中修复。

以下代码导致delegate?.thing()行上的EXC_BAD_ACCESS:

@class_protocol protocol Fooable {
  func foo()
}

class Bar : Fooable {
  func foo() {
  }
}

weak var delegate: Fooable?

let bar = Bar()
delegate = bar
delegate?.foo()

但是一切似乎都适合我。为了使变量为weak,它必须具有可选类型。因此变量delegate是可选的。弱变量的类型也必须是类类型,因此我将协议作为类协议。由于我使用可选链接,我希望它1)为nil,什么都不做,或2)不是nil,并调用方法,这应该成功。然而,它崩溃了。

是否可选链接不是原子的,并且不保留表达式,并且在检查nil和后续调用之间以某种方式取消分配对象?

有趣的是,如果您删除变量bar并将其直接指定为delegate = Bar(),则崩溃就会消失。这实在令人困惑,因为将表达式赋给变量然后分配变量并直接指定表达式通常应该表现相同。

2 个答案:

答案 0 :(得分:4)

我怀疑weak var delegate: Fooable?无效的原因是因为使用可选链接的代码行正在检查协议一致性。

根据Apple Swift编程手册:

  

“即使您没有与Objective-C互操作,也需要标记   你希望能够使用@objc属性的协议   检查协议一致性。“

如果您将@class_protocol替换为@objc,则不应该崩溃。另外,根据手册,使用@objc只允许类采用协议(没有结构或枚举一致)。

答案 1 :(得分:0)

就像@PartiallyFinite一样,我也必须使用代码。 Apple的iBook on Swift对此有所了解可能有所帮助(使用名为ExampleProtocol的协议和符合该协议的类SimpleClass): "即使变量protocolValue具有SimpleClass的运行时类型,编译器也将其视为给定类型的ExampleProtocol。这意味着除了协议一致性之外,您不会意外地访问该类实现的方法或属性。“

那就是说,你应该能够在你的委托上调用foo()(除非它在调用它之前不会消失),但是记住这里的委托声明是类型Fooable ?,而不是Bar,引擎盖下。这可能是一个错误,但我通过输入:

让它工作
weak var delegate: Bar? = bar
delegate?.foo()