weak
和 unowned
引用都不会对所引用的对象产生强引用(也就是说,它们不会增加引用计数以防止 ARC 释放所引用的对象)。
但是为什么有两个关键字呢?这与 Swift 语言内置的可选类型有关。简单来说,可选类型 提供了内存安全性(这与 Swift 的构造器规则 配合非常好,这些规则严格限制以提供此类好处)。
weak
引用允许其变为 nil
的可能性(当所引用的对象被释放时,这会自动发生),因此您的属性类型必须是可选的 - 因此,作为程序员,您必须在使用它之前检查它(基本上编译器尽可能地强制您编写安全代码)。
unowned
引用假设在其生命周期内永远不会变为nil
。 unowned
引用必须在初始化期间设置-这意味着该引用将被定义为非可选类型,可以安全地使用而无需检查。 如果某种方式正在引用的对象被释放,则当使用unowned
引用时,应用程序将崩溃。
来自Apple文档:
每当该引用在其生命周期中的某个时间点可能变为
nil
时,请使用弱引用。 相反,当您知道引用在初始化后永远不会为nil
时,请使用unowned
引用。
在文档中,有一些示例讨论保留周期以及如何打破它们。 所有这些示例都是从文档中提取的。
weak
关键字的示例:
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
}
class Apartment {
let number: Int
init(number: Int) { self.number = number }
weak var tenant: Person?
}
现在,为大家带来一些ASCII艺术(你应该去查看文档 - 他们有漂亮的图表):
Person ===(strong)==> Apartment
Person <==(weak)===== Apartment
class Customer {
let name: String
var card: CreditCard?
init(name: String) { self.name = name }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) { self.number = number; self.customer = customer }
}
Customer
类具有可选的card
属性,但CreditCard
类具有非可选(且不拥有)的customer
属性。Customer ===(strong)==> CreditCard
Customer <==(unowned)== CreditCard
类 Apartment {
let number: Int
init(number: Int) { self.number = number }
weak var tenant: Person?
}
- Justin Levi Winterweak var Person?
和var Person?
之间的区别是什么? - netwireQ1. “未拥有引用(Unowned Reference)”与“弱引用(Weak Reference)”有什么不同?
弱引用:
弱引用是一种不会对所指实例产生强引用的引用,因此不会阻止 ARC 销毁被引用的实例。由于弱引用允许具有“无值”,您必须将每个弱引用声明为可选类型。 (Apple 文档)
未拥有引用:
与弱引用类似,未拥有引用也不会对所指实例产生强引用。但与弱引用不同的是,未拥有引用始终假定具有值。因此,未拥有引用始终被定义为非可选类型。 (Apple 文档)
何时使用:
只有在该引用在其生命周期内的某些时间点上可以成为 nil 时,才使用弱引用。相反,在初始化完成后,您知道引用永远不会是 nil 时,请使用未拥有引用。 (Apple 文档)
Q2. 何时使用“未拥有引用”是安全的?
如上所述,未拥有引用始终假定具有值。因此,只有在您确定该引用永远不会是 nil 时,才应使用它。Apple 文档通过以下示例阐述了未拥有引用的使用案例。
设想我们有两个类 Customer 和 CreditCard。客户可以没有信用卡,但信用卡没有客户就不存在,即可以认为信用卡始终有客户。因此,它们应该具有以下关系:
class Customer {
var card: CreditCard?
}
class CreditCard {
unowned let customer: Customer
}
Q3. “无主引用”像C/C++的“悬空指针”一样存在安全风险吗?
我认为不会。unowned
来表示父对象的属性。反之则使用weak
。@myxtic解释得很好!unowned
引用只是保证有值的weak
引用! - Saif从链接中提取出以下内容:
几点结论
未拥有引用是一种在两个对象之间存在相同生命周期关系的情况下使用的弱引用,当一个对象只能被另一个对象拥有时。这是一种创建对象与其属性之间不可变绑定的方式。
在中级 Swift WWDC 视频中给出的示例中,一个人拥有一张信用卡,而一张信用卡只能有一个持有者。在信用卡上,人不应该是一个可选属性,因为你不希望有一张只有一个所有者的信用卡漂浮在外。你可以通过将信用卡上的持有者属性设置为弱引用来打破这个循环,但这也需要将其设置为可选的,并且是可变的(而不是常量)。在这种情况下,未拥有引用意味着虽然信用卡对于人没有所有权,但它的生命周期取决于人。
class Person {
var card: CreditCard?
}
class CreditCard {
unowned let holder: Person
init (holder: Person) {
self.holder = holder
}
}
当您确定您在访问self
时,self
永远不会是nil
时,请使用unowned
。
例如(当然,您可以直接从MyViewController
添加目标,但这只是一个简单的例子):
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let myButton = MyButton { [unowned self] in
print("At this point, self can NEVER be nil. You are safe to use unowned.")
print("This is because myButton can not be referenced without/outside this instance (myViewController)")
}
}
}
class MyButton: UIButton {
var clicked: (() -> ())
init(clicked: (() -> ())) {
self.clicked = clicked
// We use constraints to layout the view. We don't explicitly set the frame.
super.init(frame: .zero)
addTarget(self, action: #selector(clicked), for: .touchUpInside)
}
@objc private func sendClosure() {
clicked()
}
}
当你访问 self
时,存在可能它为 nil
的情况下,请使用 weak
。
例如:
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NetworkManager.sharedInstance.receivedData = { [weak self] (data) in
print("Can you guarentee that self is always available when the network manager received data?")
print("Nope, you can't. Network manager will be alive, regardless of this particular instance of MyViewController")
print("You should use weak self here, since you are not sure if this instance is still alive for every")
print("future callback of network manager")
}
}
}
class NetworkManager {
static let sharedInstance = NetworkManager()
var receivedData: ((Data) -> ())?
private func process(_ data: Data) {
// process the data...
// ... eventually notify a possible listener.
receivedData?(data)
}
}
unowned
的缺点:
weak
更高效。weak
的缺点:
unowned
更安全(因为它不会崩溃)。如果你不确定,使用 weak
。等等,我的意思是在 StackOverflow 上询问你的情况下应该怎么做!在不应该使用 weak 的情况下始终使用 weak 只会让你和代码读者感到困惑。
unowned
,对于苹果的类,使用weak
,因为我们无法确定它确切的作用。 - onmyway133