方法闭包是否保留了swift中的实例?

问题描述 投票:3回答:3

在swift中,我可以使用实例方法作为闭包,例如,将方法分配给回调

self.someView.someCallback = self.doSomething

那么,selfself.doSomething中强烈引用了吗?上面的行是否创建了一个参考循环?

swift closures automatic-ref-counting
3个回答
2
投票

根据您的代码段,有两种可能的方案:

  1. 如果doSomethingself的实例方法,那么,是的,该行建立了一个强引用。请记住,Closures are Reference Types。您可以轻松确认这一点,并且很容易通过经验确认。考虑: class ViewController: UIViewController { var foo: (() -> Void)? override func viewDidLoad() { super.viewDidLoad() foo = bar foo?() } func bar() { ... } } 如果我呈现和关闭此视图控制器三次,然后使用Xcode的“调试内存图”,我将看到这三个实例仍在内存中停留(在左侧),如果我选择一个,它将向我显示强引用在中心面板中直观地循环: enter image description here 因为我使用了“Malloc堆栈”功能,所以在右侧面板上我可以准确地看到延迟强引用的位置,即在viewDidLoad中设置闭包。
  2. 但是,如果doSomething不是一个函数,而是一个闭包,那么该行本身并不会建立一个强引用,而是它成为一个问题,即闭包本身是否指的是self,如果是的话,是否有[weak self][unowned self]捕获列表。有关更多信息,请参阅Strong Reference Cycles for Closures

1
投票

为了有一个保留周期,你需要在每个方向上有一个强有力的参考,即:

对象A强烈引用对象B.

对象B强烈引用对象A.

假设您共享的代码中的self是一个视图控制器,并假设someView是对视图的强引用,我们可以这样说:

对象A(视图控制器)强烈引用对象B(某些视图)

现在,如果对象B(某些视图)具有强烈的参考回到视图控制器,您将有一个保留周期。

假设doSomething是ViewController中的一个方法,而不是一个闭包,那么你将有一个保留周期

检查这个问题的简单方法是在Some View和View Controller中实现deinit,如下所示:

class SecondViewController: UIViewController {

    var someView: CustomView?

    override func viewDidLoad() {
        super.viewDidLoad()

        someView = CustomView(frame: view.frame)
        someView?.someCallback = doSomething
    }

    func doSomething() {
    }

    deinit {
        print(#function)
    }
}

final class CustomView: UIView {
    var someCallback: (() -> Void)?

    deinit {
        print(#function)
    }
}

您将看到print上的deinits永远不会在控制台中打印出来。但是改变你将someCallback分配给的方式:

someView?.someCallback = { [weak self] in
    self?.doSomething()
}

将导致deinit运行,从而打破保留周期

编辑:

甚至,作为替代方案:

weak var weakSelf = self
someView?.someCallback = weakSelf?.doSomething

(即使这是使用弱引用,因为在执行someCallback的赋值时评估此表达式,而不是在执行它时,这仍将成为strong引用) - 谢谢@Rob


0
投票

在Swift中,声明一个闭包类型变量,并希望为它分配一个func,防止出现保留问题,只需按照以下步骤操作,一整天都在搜索答案,渴望分享:

self.someView.someCallback = { [unowned self] in self.doSomething() }

© www.soinside.com 2019 - 2024. All rights reserved.