Swift中的unowned(safe)和unowned(unsafe)有什么区别?

p5cysglq  于 2023-09-30  发布在  Swift
关注(0)|答案(5)|浏览(146)

苹果的Swift Programming Language Guide提到了 * 捕获说明符 * unowned(safe)unowned(unsafe),以及weakunowned
我(认为我)理解weakunowned之间的区别; unowned(safe)unowned(unsafe)有什么区别?指南没有说。
请不要依赖于简单地陈述一个Objective-C等价物。

mwyxok5s

mwyxok5s1#

据我所知,虽然我无法从Apple找到确切的来源,但unowned可以分为两种风格,safeunsafe
unownedunowned(safe):它是一个特殊 Package 的引用,当引用一个释放的示例时,它将抛出一个异常。
特殊情况为unowned(unsafe):它是Objective C的@property (assign)__unsafe_unretained的Swift等价物。它不应该在Swift程序中使用,因为它的目的是连接到用Objective C编写的代码。
因此,在查看可可类的导入 Package 器时,您将看到unowned(unsafe),但除非必要,否则不要使用它,您将知道何时必须使用它。

更新

__unsafe_unretained是一个简单的指针。它不知道所指向的示例何时被释放,因此当它被解除引用时,底层内存可能是垃圾。
如果您有一个缺陷,其中使用了一个释放的__unsafe_unretained变量,您将看到不稳定的行为。有时,足够的内存位置足够好,所以代码将运行,有时它会被部分覆盖,所以你会得到非常奇怪的崩溃,有时,内存位置将包含一个新的对象,所以你会得到无法识别的选择器异常。
过渡到ARC发行说明
__unsafe_unretained指定了一个引用,它不会使被引用的对象保持活动状态,并且在没有对该对象的强引用时不会设置为nil。如果它引用的对象被释放,指针将保持悬空状态。

ni65a41a

ni65a41a2#

以下是Apple Developer Forums的一段话:

unowned vs unowned(safe) vs unowned(unsafe)

unowned(safe)是一个非所有权引用,它在访问时Assert对象仍然是活动的。它有点像一个弱可选引用,每次访问时都用x!隐式展开。unowned(unsafe)类似于ARC中的__unsafe_unretained--它是一个无主引用,但没有运行时检查对象在访问时是否仍然存活,因此悬空引用将进入垃圾内存。unowned目前始终是unowned(safe)的同义词,但其目的是在禁用运行时检查时,在-Ofast构建中将其优化为unowned(unsafe)

ewm0tg9j

ewm0tg9j3#

当变量已与属性一起被解分配时,访问该变量:

无主

  • 程序知道它是无效的,并立即崩溃。
  • 行为被定义。

unowned(unsafe)

  • 程序什么都不知道。
  • 它可能会立即崩溃。
  • 它可以访问未知的内存地址,并有奇怪的状态,直到它死在意外的位置。
  • 行为为undefined。生活越来越艰难。
km0tfn4u

km0tfn4u4#

简单的定义。这样就能消除误会了
--无主属性:如果您试图在它所引用的示例被释放后访问无主引用,则程序将崩溃。
-- unowned(Unsafe)属性:如果在示例所引用的示例被释放后尝试访问不安全的无主引用,则程序将尝试访问该示例以前所在的内存位置,这是不安全的操作。(不保证这将执行或崩溃)

r1wp621o

r1wp621o5#

用通俗的语言
unowned(safe)或简称为unowned-如果我们尝试引用已释放的对象,则使应用程序崩溃。
unowned(unsafe)-不要使应用程序崩溃,而是尝试查找在去初始化之前存储引用对象的内存位置。
例如-

class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) {
        self.name = name
    }
    deinit {
        print("\(name) is being deinitialized")
        print("It's Credit card is - ", card)
    }
}

class CreditCard {
    let number: UInt64
    unowned(unsafe) let customer: Customer
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit {
        print("Card #\(number) is being deinitialized")
        print("It's customer is - ", customer.name)
    }
}

var customer: Customer? = Customer(name: "Stackoverflow")
customer!.card = CreditCard(number: 1234_5678_9012_3456, customer: customer!)
customer = nil

当你在playground中运行这段代码时,你会得到以下输出:

Stackoverflow is being deinitialized
It's Credit card -  Optional(__lldb_expr_16.CreditCard)
Card #1234567890123456 is being deinitialized
It's customer -  Stackoverflow

这里要检查的主要事情是,即使Stackoverflow被取消初始化,但我们仍然可以在CreditCard的deinit调用中打印它
如果您尝试使用unowned而不是unowned(unsafe)调用相同的代码,则它将崩溃,并显示以下日志

Stackoverflow is being deinitialized
It's Credit card -  Optional(__lldb_expr_20.CreditCard)
Card #1234567890123456 is being deinitialized
Fatal error: Attempted to read an unowned reference but object 0x600000291830 was already deallocated

相关问题