Jak*_*Lin 455 ios automatic-ref-counting swift
在WWDC 2014会议403 中级Swift和成绩单中,有以下幻灯片

在这种情况下,发言人说,如果我们不在[unowned self]那里使用,那将是内存泄漏.这是否意味着我们应该始终使用[unowned self]内部封闭?
在Swift Weather应用程序的ViewController.swift的第64行,我不使用[unowned self].但我通过使用一些@IBOutlet像self.temperature和更新UI self.loadingIndicator.它可能没问题,因为@IBOutlet我所定义的都是weak.但为了安全起见,我们应该一直使用[unowned self]吗?
class TempNotifier {
var onChange: (Int) -> Void = {_ in }
var currentTemp = 72
init() {
onChange = { [unowned self] temp in
self.currentTemp = temp
}
}
}
Run Code Online (Sandbox Code Playgroud)
dre*_*wag 851
不,肯定有时候你不想使用它[unowned self].有时你希望闭包捕获self,以确保在调用闭包时它仍然存在.
如果要进行异步网络请求,则需要self在请求完成时保留闭包.否则该对象可能已取消分配,但您仍希望能够处理完成请求.
unowned self或weak self您真正想要使用的唯一时间,[unowned self]或者[weak self]您何时创建强大的参考周期.一个强大的参考周期是当存在一个所有权循环,其中对象最终彼此拥有(可能通过第三方),因此它们将永远不会被释放,因为它们都确保彼此坚持.
在闭包的特定情况下,您只需要意识到在其中引用的任何变量都由闭包"拥有".只要封闭物周围,这些物体就可以保证在周围.阻止这种所有权的唯一方法就是做[unowned self]或[weak self].因此,如果一个类拥有一个闭包,并且该闭包捕获了对该类的强引用,那么在闭包和类之间有一个强大的引用循环.这还包括如果该类拥有拥有该闭包的东西.
在幻灯片的示例中,TempNotifier通过onChange成员变量拥有闭包.如果他们没有申报self的unowned,关闭也将自己self创造一个有力的参考周期.
unowned和之间的区别weak之间的区别unowned和weak是weak被声明为可选,而unowned不是.通过声明它weak你可以处理在某些时候它可能在闭包内部的情况.如果您尝试访问unowned恰好为nil 的变量,则会导致整个程序崩溃.因此,只有unowned当你肯定变量将永远存在于闭包附近时才使用
Umb*_*ndi 185
我写了一篇关于这个问题的文章,扩展了这个答案(查看SIL以了解ARC的作用),请在此处查看.
之前的答案并没有真正给出关于何时使用其中一个的简单规则以及为什么,所以让我添加一些东西.
无主论者或弱论者归结为变量的生命周期和引用它的闭包的问题.
您可以有两种可能的情况:
闭包具有相同的生命周期,因此只有在变量可达时才能访问闭包.变量和闭包具有相同的寿命.在这种情况下,您应该将引用声明为unowned.一个常见的例子是[unowned self]在许多小闭包的例子中使用,这些闭包在父母的上下文中做某事,而在其他任何地方都没有被引用不会比父母长.
闭包生命周期独立于变量之一,当变量不再可达时,仍然可以引用闭包.在这种情况下,您应该将引用声明为弱并在使用之前验证它不是nil(不要强制解包).一个常见的例子是[weak delegate]你可以在闭包引用一个完全不相关(生命周期)的委托对象的一些例子中看到.
那么,大多数时候你会/你应该使用哪种?
无主是更快,允许不变性和非可选性.
如果您不需要弱,请不要使用它.
* 通常也称为无主(安全),表示在访问无主引用之前执行运行时检查(导致无效引用崩溃).
pos*_*sen 94
我想我会专门为视图控制器添加一些具体的例子.许多解释,不仅仅是Stack Overflow,都非常好,但是我用现实世界的例子做得更好(@drewag在这方面有一个良好的开端):
weak,因为它们很长寿.视图控制器可以在请求完成之前关闭,因此self在调用闭包时不再指向有效对象.如果你有一个闭包来处理按钮上的事件.这可能是unowned因为只要视图控制器消失,按钮和它可能引用的任何其他项目self就会同时消失.闭合块也将同时消失.
class MyViewController: UIViewController {
@IBOutlet weak var myButton: UIButton!
let networkManager = NetworkManager()
let buttonPressClosure: () -> Void // closure must be held in this class.
override func viewDidLoad() {
// use unowned here
buttonPressClosure = { [unowned self] in
self.changeDisplayViewMode() // won't happen after vc closes.
}
// use weak here
networkManager.fetch(query: query) { [weak self] (results, error) in
self?.updateUI() // could be called any time after vc closes
}
}
@IBAction func buttonPress(self: Any) {
buttonPressClosure()
}
// rest of class below.
}
Run Code Online (Sandbox Code Playgroud)Ten*_*Jay 68
如果封闭使用自我可能是零[弱自我].
如果自我永远不会在闭包中使用[无主自我].
Apple Swift文档有一个很棒的部分,其中的图像解释了在闭包中使用strong,weak和unowned之间的区别:
Val*_*gin 49
以下是来自Apple Developer论坛的精彩报价,描述了美味的细节:
unownedvs unowned(safe)vsunowned(unsafe)
unowned(safe)是一个非拥有的引用,在访问时声明对象仍然存在.它有点像一个弱的可选引用,x!每次访问它时都会隐式解包.unowned(unsafe)就像__unsafe_unretained在ARC 中一样,它是一个非拥有的引用,但没有运行时检查对象在访问时仍然存活,因此悬空引用将进入垃圾内存.unowned始终是unowned(safe)当前的同义词,但目的是unowned(unsafe)在-Ofast禁用运行时检查时,它将在构建中进行优化.
unowned VS weak
unowned实际上使用的实现比简单得多weak.Native Swift对象带有两个引用计数,unowned引用会使无主引用计数而不是强 引用计数.当强引用计数达到零时,该对象被取消初始化,但在无主参考计数也达到零之前,它实际上不会被释放 .当存在无主引用时,这会使内存保持稍长时间,但这在unowned使用时通常不会成为问题,因为相关对象应该具有接近相等的生命周期,并且它比侧面更简单且开销更低.基于表的实现,用于归零弱引用.
更新:在现代斯威夫特weak在内部使用的相同的机制unowned呢.所以这种比较是不正确的,因为它将Objective-C weak与Swift 进行了比较unonwed.
拥有引用达到0后保持内存存活的目的是什么?如果代码在取消初始化后尝试使用无主引用对对象执行某些操作会发生什么?
内存保持活动状态,因此其保留计数仍然可用.这样,当有人试图保留对无主对象的强引用时,运行时可以检查强引用计数是否大于零,以确保保留对象是安全的.
对象拥有或拥有的引用会发生什么?当它被取消初始化时,它们的生命周期是否与对象分离,或者它们的内存是否也会保留,直到在释放最后一个无主引用后释放对象为止?
一旦对象的最后一个强引用被释放,就会释放该对象拥有的所有资源,并且运行它的deinit.无主引用只保留内存,而不是带引用计数的头,它的内容是垃圾.
兴奋,是吧?
Saf*_*ive 36
这里有一些很棒的答案.但最近对Swift如何实现弱引用的更改应该改变每个人的弱自我与无主自我使用决策.以前,如果你需要使用无主自我的最佳表现优于弱自我,只要你可以确定自我永远不会是零,因为访问无主的自我比访问弱自我快得多.
但Mike Ash已经记录了Swift如何更新弱变量的实现以使用边表以及这如何显着改善弱自我表现.
https://mikeash.com/pyblog/friday-qa-2017-09-22-swift-4-weak-references.html
既然自我弱化并没有显着的性能损失,我相信我们应该默认使用它.弱自我的好处是它是可选的,这使得编写更正确的代码变得容易得多,这基本上是Swift是如此优秀语言的原因.你可能认为你知道哪些情况对于使用无主的自我是安全的,但是我回顾很多其他开发人员代码的经验是,大多数情况下都没有.我已经修复了许多崩溃,其中无主自我被释放,通常在后台线程在控制器被释放后完成的情况下.
错误和崩溃是编程中最耗时,最痛苦和最昂贵的部分.尽力编写正确的代码并避免使用它们.我建议永远不要强制打开选项,永远不要使用无主的自我而不是弱自我.你不会失去任何错过时间的力量解开和无主的自我实际上是安全的.但是,通过消除难以发现和调试崩溃和错误,您将获得很多收益.
根据苹果文档
弱引用始终是可选类型,并在它们引用的实例被释放时自动变为 nil。
如果捕获的引用永远不会变为 nil,则应始终将其捕获为无主引用,而不是弱引用
例子 -
// if my response can nil use [weak self]
resource.request().onComplete { [weak self] response in
guard let strongSelf = self else {
return
}
let model = strongSelf.updateModel(response)
strongSelf.updateUI(model)
}
// Only use [unowned self] unowned if guarantees that response never nil
resource.request().onComplete { [unowned self] response in
let model = self.updateModel(response)
self.updateUI(model)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
143546 次 |
| 最近记录: |