当我们将一个对象的实例作为参数传递给一个方法时,该方法在该对象内部定义,如下面的代码所示,是否会创建一个保留周期?
self.someMethod(self)
答案 0 :(得分:3)
如果您引用班级的实例方法:
class FooBar {
func foo() {
print("Foo")
}
func bar() {
self.foo()
}
}
隐含“自我”,编译器不需要它。即使您使用foo()
而不使用self.
,它仍然会隐式引用。
没有保留周期,因为您在同一个对象上从一个实例方法调用另一个实例方法。
自我让你陷入困境的是“逃避”关闭。转义闭包是一个闭包,传递给另一个对其强烈引用的对象。完成处理程序通常可以转出封装。
因此,当您调用一个带有完成处理程序的函数并且该完成处理程序是一个转义闭包时,另一个对象将获得该闭包的所有权。
现在,如果闭包使用self,则意味着闭包还拥有“self”
typealias completionHandler = () -> ()
class AClass {
lazy var someOtherObject = SomeOtherObject()
var value: Int = 0
func callClosure() {
someOtherObject.doSomething(completion: {
self.foo = self.foo + 1
}
}
}
class SomeOtherObject {
var myCompletionHandler: () -> ()
func doSomething( completion: @escaping completionHandler) {
myCompletionHandler = completion
//pretend there is code here to call an async method and invoke completion
}
}
以上使用self 确实会导致保留周期。方法如下:
AClass
的实例会创建一个SomeOtherObject
类型的对象,并保持对它的强大/拥有引用。只要SomeOtherObject
的实例存在,AClass
就不会消失。
当我们调用callClosure()
时,我们传入一个完成处理程序。 SomeOtherObject接受闭包的所有权。
现在,由于闭包的代码引用self
,因此闭包取得self
的所有权。我们现在在拥有SomeOtherObject
的AClass对象,拥有闭包的SomeOtherObject
和拥有AClass
对象的闭包之间有一个3向保留周期。 / p>
您可以通过向闭包添加“捕获列表”来修复保留周期。这是一个闭包使用的变量列表,应该被弱化。修改后的代码可能如下所示:
func callClosure() {
//the `[weak self]` capture list below makes self weak inside the closure
someOtherObject.doSomething(completion: { [weak self] in
///use a guard to map weakSelf to strongSelf if it isn't nil, or return
//if self has been deallocated and is now nil.
guard let strongSelf = weakSelf else { return }
strongSelf.foo = strongSelf.foo + 1
}
}