为什么Swift不允许对非可选类型使用弱引用?

3
这不仅是出于好奇,我也有一种可能会误解Swift中弱引用的感觉。
假设我从一个视图控制器创建一个类,并将其引用传递给初始化程序:
class = MyClass(vc: self)

由于故事板和窗口已经保留对此视图控制器的引用,因此MyClass拥有弱引用似乎是合理的(出于与在IB中创建的所有引用默认为弱引用相似的原因):

class MyClass: NSObject {
    private weak var viewController: UIViewController

    init(vc: UIViewController) {
       self.viewController = vc
       super.init
    }

    func setViewController(_ vc: UIViewController) {
       self.viewController = vc
    }

    ...
}

然而,这段代码出现编译错误,因为viewController变量不是可选的。所以我不得不在viewController声明中添加'!'并删除初始化程序,只留下setViewController,看起来相当不自然。
为什么不允许非可选的弱数据?

1
  1. "由于Storyboard和窗口已经保留了对此视图控制器的引用,因此MyClass拥有一个弱引用似乎是合理的"。不,这不是一个好的理由。如果您的对象没有对vc的拥有关系,则应使用弱引用,以阻止保留循环。
  2. "出于类似的原因,IB中创建的所有引用默认都是弱引用",但现在更倾向于使用强引用。
  3. 当对它的强引用过期时,您希望在引用viewController时发生什么?
- Alexander
亚历山大:2)如果偏爱强引用,为什么IB默认采用弱引用?纯粹是怀旧老时光的原因吗?:) 正如你所提到的,弱引用有助于阻止保留循环。现代Java不使用引用计数,因此它不提供弱引用。相反,Swift使用引用计数,因此有时需要弱引用。 - cyanide
亚历山大 3) 你能解释一下“强引用过期”的意思吗? - cyanide
“它是故事板拥有它”——错了,不是这样的。UIStoryboard反序列化VC的新实例,然后放弃其所有权。如果它是窗口的contentViewController,则窗口拥有它。如果合适,你的对象也可以拥有它。 - rob mayoff
“对象如何拥有自己”… 嗯,它可以保持对自身的强引用。但这不是你想要的。看起来你要么想让VC拥有该对象,要么想让该对象拥有VC。如果你想让VC拥有该对象,并希望该对象引用VC,则为避免保留循环,该对象的引用必须是weakunowned。如果是weak,则必须是Optional。如果是unowned,则不能是Optional - rob mayoff
显示剩余5条评论
1个回答

11

所谓的weak变量是指该变量不会增加对象的引用计数,更重要的是,在引用的对象被释放时,该变量的值将自动设置为nil

由于变量必须允许为空值,因此必须是可选类型。这就是为什么不允许使用非可选型的弱引用变量。

不要声明viewController为隐式解包(使用!)。请将其定义为真正的可选类型(使用?)。


问题不在于什么是弱类型,或如何避免编译错误。问题在于为什么禁止使用弱可选类型。我相信,我已经表达得很清楚了。 - cyanide
顺便提一下,把 "!" 改成 "?" 不应该有任何影响,除了每次需要显式解包视图控制器。 - cyanide
1
我的回答特别解释了为什么弱变量必须是可选的。简而言之,因为只有可选项才能为nil,而弱变量可以为nil。 - rmaddy
1
使用!是错误的,因为这样的变量永远不应该是nil。 - rmaddy
好的,非可选变量不能被设置为nil,因此它的引用计数从不为0。这表明标准的引用计数方法不适用于非可选类型。将其标记为答案,即使它引发了更多的问题 :) 好消息是,我可以安全地使用非可选类型,而不必担心会导致死锁。 - cyanide
1
@cyanide 抱歉,但你的结论是错误的。对于引用类型的非可选(当然也不是弱引用)变量,完全涉及标准引用计数,并且肯定会导致引用循环(我相信这就是你所说的“死锁”)。如果您不希望变量引用涉及引用计数,请使用弱引用。如果您不希望变量引用可能导致引用循环,请使用弱引用。由于弱引用变量可以为nil,因此弱引用变量也必须是可选的。 - rmaddy

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