当我们将一个对象的实例作为参数传递给一个方法时,该方法定义在该对象内部,如下面的代码所示,它是否会创建一个保留循环?
self.someMethod(self)
Run Code Online (Sandbox Code Playgroud)
如果您引用类的实例方法:
class FooBar {
func foo() {
print("Foo")
}
func bar() {
self.foo()
}
}
Run Code Online (Sandbox Code Playgroud)
“self”是隐含的,编译器不需要它。即使您foo()不使用self.,它仍然隐式地引用 self 。
不,没有保留循环,因为您是在同一对象上从一个实例方法调用另一个实例方法。
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
}
}
Run Code Online (Sandbox Code Playgroud)
self 的上述使用确实会导致保留循环。就是这样:
和 instance ofAClass创建一个类型的对象SomeOtherObject并保持对它的强/拥有引用。在SomeOtherObject只要不会消失作为实例AClass的生命。
当我们调用 时callClosure(),我们传入一个完成处理程序。SomeOtherObject 拥有闭包的所有权。
现在,由于闭包的代码引用了self,闭包获得了 的所有权self。我们现在有一个3路的ACLASS对象,它拥有与保留周期SomeOtherObject的SomeOtherObject,该公司拥有的封闭,并关闭,该公司拥有的AClass对象。
您可以通过向闭包添加“捕获列表”来修复保留周期。这是一个闭包使用的变量列表,应该被弱持有。修改后的代码可能如下所示:
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
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1895 次 |
| 最近记录: |