Swift自动引用计数和块

6
我正在尝试一个简单的示例,如下所示: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-XID_88 以下是我的代码。(忽略其他可能存在的代码,此处是在空的UIViewcontroller的viewDidLoad中编写的)
    dispatch_async(dispatch_get_main_queue()) {
        [unowned self] in
        println(self)
    }

我不明白为什么在运行该程序时会崩溃。
  • 线程#1:tid=0x1a796,0x00284d18 libswiftCore.dylib`_swift_release_slow + 8,队列= 'com.apple.main-thread',停止原因=EXC_BAD_ACCESS(code=1, address=0x458bc681)
最新的beta(5)有什么变化导致这个程序不再受支持吗? 谢谢。
编辑: 有趣的是,这段代码在Objc上可以工作。
__weak MyViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"%@", weakSelf);
});

编辑2: 这个链接上的解释:Shall we always use [unowned self] inside closure in Swift 关于weak和unowned的区别是错误的。

不仅仅是weak会变成nil,而unowned则不会。如果是那样的话,这个也应该会崩溃:

  dispatch_async(dispatch_get_main_queue()) {
            [weak self] in
            println(self)
        }

但实际上,它并没有打印 nil ,而是打印了指针,因此它并不是 nil。

2
Swift编程语言中得知:“如果您尝试在实例被释放后访问未拥有的引用,将会触发运行时错误。” - Rob
Unowned 表示 self 不会被保留,但如果 self 被释放并且 unowned 被使用,则会导致崩溃。如果可能被释放,则使用 strong 或 weak。 - SomeGuy
2
你之前的评论,认为 [weak self] 会导致崩溃是不正确的。在这种情况下,self 是一个可选项。你应该期望上述代码打印出 nil 或类似的内容。unowned 的意思是“我保证它不会是 nil,如果是,就让我崩溃。”而 weak 的意思是“它是可选项,所以 nil 是可以接受的。” - Rob Napier
@RobNapier 不是它没有崩溃,而是它还打印了指针值,而且不是nil。 - Wak
这个链接上的解释:在 Swift 中,我们是否应该总是在闭包内使用 [unowned self] 来区分 weak 和 unowned 是错误的。它为什么是错的? - user102008
@RobNapier - 回答有点含糊,但我喜欢它。;-) - clearlight
1个回答

9

[无主引用 self] 使得闭包不会对 self 创建强引用,也不会在它释放后自动将其设置为nil。当异步方法被执行时,self已经被释放了。这就是为什么会导致崩溃。

在一次性异步调用中使用 unowned 是没有意义的。最好捕获一个强引用确保它一直存在。因为 self 不拥有该闭包,所以仍然不会产生强引用循环。

附注:这不能是你代码的全部,因为你的代码中没有定义 self

unownedweak 是两个不同的东西。在 Objective-C 中,unowned 被称为 unsafe unretained。在两种语言中都可以使用 weakweak 表示运行时会在对象释放时自动将引用转换为 nil。而 unownedunsafe unretained 表示它不会为您设置为nil(这就是为什么在Objective-C 中称之为 "unsafe")。

Unowned 应仅在对象永远不会被释放的情况下使用。在这些情况下,使用 weak

请记住,如果您将变量捕获为 Swift 中的 weak,则引用将变为可选类型,因此需要解包才能使用:

dispatch_async(dispatch_get_main_queue()) {
    [weak self] in
    if let actualSelf == self {
         // do something with actualSelf
    }
    // you can still print the "wrapped" self because it is fine to print optionals
    // even if they are `nil`
    println(self)
}

但是需要明确的是,在这种情况下最好仍然使用强引用:
dispatch_async(dispatch_get_main_queue()) {
    println(self)
}

1
@Wak,我无法确定差异可能是什么。它可能只是竞争条件。然而,我关于weakunowned/ unsafe unretainedstrong的描述是百分之百准确的。重要的是是否在Swift中删除[weak self] in可以解决您的崩溃。 - drewag
1
在ObjC中没有unowned,因此当您说它可以在那里工作时,不清楚您的意思。weakstrong都不应该崩溃。 - Rob Napier
1
在Objective-C中,@RobNapier所说的“unowned”被称为“unsafe unretained”。它确实存在,只是名字不同。 - drewag
在Objective-C中,unowned被称为unsafe unretained。但是,在Swift中,当对象被释放时使用unowned引用会导致运行时崩溃,这是由Swift语言规范保证的。在Objective-C中,当对象被释放后使用unsafe_unretained引用会调用未定义的行为。 - user102008
"unowned ... 意味着它不会被设置为 nil,而是在内部以某种方式标记为无效状态,因此当您尝试使用它时,可以保证会产生运行时错误。" - user102008
显示剩余14条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接