【问题标题】:Why doesn't Xcode make outlets unowned instead of weak?为什么 Xcode 不让 outlet 无主而不是 weak?
【发布时间】:2023-03-05 13:02:01
【问题描述】:

Xcode 将 outlet 生成为带有隐式展开的弱变量,如下所示:

@IBOutlet weak var nameTextField: UITextField!

我想知道为什么它不只是让onowned var,在我的理解中 - 行为完全相同,但保持类型非可选。这两者有什么区别吗?

weak var foo: UITextField!
unowned var foo: UITextField

【问题讨论】:

  • 两阶段初始化。出口是在初始化之后分配的,因此它们必须是可选的。通常保留weakstrong 并不重要,但unowned 不正确。
  • @Sulthan 我一直想知道为什么 IBOutlet 在断点处被击中两次。所以我创建了一个项目,将一个标签拖到 viewController 中并在其上设置了一个断点。第一个断点发生在viewDidLoadinit 之前。如果我打印标签,它显示它是nil。我第二次打断点是在init 之后但仍然在viewDidLoad 之前。这次如果我打印它,它会显示:Optional<UILabel>

标签: ios swift xcode weak-references iboutlet


【解决方案1】:

weak 变量有一个默认值,即nil,因此您的代码是合法的,因为出口属性在对象创建时(出口实际连接之前)具有值。

但是unowned 变量没有默认值,您的代码将无法编译。试试看。

整个概念也是错误的。 unowned 是一个保证独立存在并且你不能没有它的东西。视图控制器视图的子视图都不满足这两个。

【讨论】:

  • 我不认为这是原因。出口被声明为弱的原因是出口的容器视图将始终对其具有强引用。它不能是无主的,因为无主对于 Objc 运行时不可用。 weak 没有默认值 nil。出口被隐式展开。所以它在访问时应该总是有非零值。
  • “因为 unowned 不适用于 Objc 运行时”@MohammadSadiq 它在 Objective-C 中是非 ARC weak
【解决方案2】:

无主类型是危险的,最好避免。无主变量等价于 Objective C 的 unsafe_unretained 类型。

如果无主引用指向的对象被释放,无主引用不会被设置为 nil。如果您稍后尝试引用该对象,您的代码将无法判断它是否仍然有效。如果你试图调用一个方法或读/写一个实例变量,如果对象已经被释放,你可能会崩溃。

(事实上,变量没有默认值,正如马特在他的回答中所说的那样。)

【讨论】:

  • 隐式解包的选项也会导致它崩溃。我的理解是 Outlets 是 unowned 的好候选,但是因为 unowned 对 Obc 运行时不可用,所以它被声明为 weak ,隐式展开。
  • 如果为 nil,隐式展开的选项确实会崩溃,但这种崩溃是有保证的、直接的和明显的。对已释放对象的无主引用会导致未定义的行为,并可能导致内存损坏,直到稍后一段时间才会出现。这类错误令人讨厌且很难找到。
  • 不,网点不适合无主。你应该避免无主引用,尽可能使用弱引用。
  • 好的。但这真的是出口薄弱和隐含展开的原因吗?因为隐式解包本身意味着它在访问时不应该为零。
  • 实际上,unowned 引用总是会在尝试访问已释放的对象时引发运行时错误(因此在这方面相当于强制解开 weak 引用)。 unowned(unsafe) 会给你带来不确定的行为。运行时知道引发运行时错误的方式实际上是因为 Swift 为无主引用保留了单独的引用计数。当强引用计数为零时,deinit 会被调用,然后会从unowned 访问中引发运行时错误。然后当unowned 引用计数达到零时,对象才会实际上被释放。
【解决方案3】:

是的,有区别。除了默认值问题,还有一种方法可以检查weak 值当前是否存在:

if let nameTextField = nameTextField {
    // do smth
}

另一方面,我认为没有办法检查unowned 是否存在并且可以访问。无论何时使用unowned,它都应该一直存在,而IBOutlet 则不是这样。在从情节提要加载视图控制器之前,不会设置出口。

希望这会有所帮助!

【讨论】:

    【解决方案4】:

    unowned var foo: UITextField 应该在视图控制器初始化期间初始化,但这是不可能的,因为只能在创建视图后初始化 outlet,并且只有在显示视图控制器时才创建视图(更准确地说是在访问 view 属性时)。

    【讨论】:

    • 是的,我认为这就是它改用weak 的原因。 unowned 在初始化方面的行为与任何其他属性一样。所以他们需要做可选的unowned,当我们有weak时这没有多大意义:)
    【解决方案5】:

    以前选项不能是unowned。这现在是可能的,所以unowned 是合适的。这可能不是自动完成的,因为它会使某人感到困惑。

    @IBOutlet private unowned var uiObject: UIObject!
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-12
      • 2016-04-10
      • 1970-01-01
      • 2014-11-20
      • 2011-09-09
      相关资源
      最近更新 更多