功能编程:闭包参考周期和修复
Article_1链接→ 功能迅速:关于闭包的全部。
Article_2链接→ iOS中的Lazy var swift。
请阅读以上两篇文章以继续。
假设您对函数式编程和闭包有很好的了解,那么让我们开始吧。
考虑一类Human
。 它具有一个init
方法,该方法接受firstName
和lastName
作为参数。 它还有一个名为fullName
的lazy var closure
,该lazy var closure
不接受任何内容并返回String
。 它是()->String
类型的。
在这里,当我们调用init方法时,将创建一个新的Human
对象。 我们将此对象分配给可选类型humanObj
。
在下一行中,当我们将humanObj
的值设置为nil
,将deinit{}
方法。 您可以看到控制台打印在deinit
方法中给出的文本。
现在,尝试在创建对象之后访问fullName
闭包。 然后尝试将对象设置为nil
。
var humanObj:人类? = Human(firstName:“ John”,lastName:“ Doe”) let fullName = humanObj?.fullName humanObj = nil
由于闭包强烈引用self
因此不会调用deinit{}
方法。
释放对象时将调用deinit方法。
解决方法
我们可以在捕获列表中使用
self
来使用weak
引用或unowned
引用来打破强引用周期。 如果您不知道什么是捕获列表,请阅读顶部提到的文章。
弱
弱引用是指不会对其引用的实例保持强大控制的引用,因此不会阻止ARC处置所引用的实例。 此行为可防止参考成为强大参考周期的一部分。
由于弱引用可能为nil
,因此捕获的变量变为可选。 因此,我们应该使用guard
来安全地拆开它:
懒惰的var fullName :()->字符串= {保护中的[弱自我] 让weakSelf =自我else {返回“”} 返回“ \(weakSelf.firstName)\(weakSelf.lastName)” }
无人
像弱引用一样,无主引用也不会对其引用的实例保持强大的控制力。 但是,与弱引用不同,当另一个实例具有相同的生存期或更长的生存期时,将使用无主引用
惰性var fullName :()->字符串= { 返回[\(self.firstName)\(self.lastName)”的[无名的 自我] }
这意味着,当我们确定引用在闭包内永远不会nil
时,我们应该使用unowned
,否则应用程序将崩溃。 因此,此处不需要进行防护检查。
我们可以对捕获列表中的任何变量使用weak
和unowned
,并可以与别名结合使用:
惰性var fullName :()->字符串= { 返回[\(unownedSelf.firstName)\(unownedSelf.lastName)” }
如何用带有参数的闭包捕获自我?
好吧,您应该在内部闭包参数之前或内部参数括号之前捕获self
。 检查下面的代码。 它说明了如何在单个参数的情况下捕获自身。 如果您有多个参数,则也可以使用括号。
重要提示:对于非转义的闭包,我们不必担心使用弱关键字或无主关键字来捕获自身。 它仅对转义的闭包有意义。
例外情况:
尽管在封闭中弱地捕获self
是一种好习惯,但并非总是必要的。 没有self
保留的封闭物可以很强地捕获它,而不会引起保留循环。 一些常见的例子是:
使用DispatchQueue
,GCD中的animation
关闭
DispatchQueue.main.async { self.doSomething() // Not a retain cycle }
DispatchQueue.main.async { self.doSomething() // Not a retain cycle }
UIView.animate(withDuration: 1) { self.doSomething() // Not a retain cycle }
UIView.animate(withDuration: 1) { self.doSomething() // Not a retain cycle }
不需要强烈捕获self
另一个有趣的地方是lazy
变量,它们不是闭包,因为它们将运行一次(或永远不会运行),然后再释放:
lazy var fullName = { return self.firstName + " " + self.lastName }() // not retained. no need to use self with weak or unowned
但是, 如果一个 lazy
变量是一个闭包 ,则需要捕获自身weakly/unowned
。 Human类中的fullName:()->String
闭包就是一个很好的例子。
请享用!!
如果您喜欢阅读这篇文章,请分享并推荐它,以便其他人可以找到💚💚💚💚💚💚!!!!
您可以在Medium上关注我以获取新文章。 在LinkedIn上与我联系。
如果您有任何评论,问题或建议,请随时在下面的评论部分中发布它们!