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

时间:2017-04-25 13:31:28

标签: swift closures automatic-ref-counting

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

self.someView.someCallback = self.doSomething

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

3 个答案:

答案 0 :(得分:2)

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

  1. 如果doSomethingself的实例方法,则是,该行建立强引用。请记住Closures are Reference Types。您可以轻松确认这一点,并且很容易通过经验确认。考虑:

    class ViewController: UIViewController {
    
        var foo: (() -> Void)?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            foo = bar
    
            foo?()
        }
    
        func bar() { ... }
    }
    

    如果我呈现并关闭此视图控制器三次,然后使用Xcode的“调试内存图”debug memory graph,我会看到这三个实例仍在内存中(在左侧),如果我选择一个,它将在中心面板中直观地显示强大的参考周期:

    enter image description here

    因为我使用了“Malloc堆栈”功能,所以在右侧面板上我可以准确地看到延迟强引用的位置,即viewDidLoad我设置该闭包的位置。

  2. 但是,如果doSomething不是一个函数,而是一个闭包,那么该行本身并不会建立一个强引用,而是它成为一个问题,即闭包本身,指的是self,如果有的话,是指是否有[weak self][unowned self]捕获列表。有关详细信息,请参阅Strong Reference Cycles for Closures

答案 1 :(得分: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上的deinit永远不会在控制台中打印出来。但是,请更改someCallback指定的方式:

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

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

修改

或者甚至,作为替代方案:

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

<击>

即使这是使用弱引用,因为在执行someCallback的赋值时评估此表达式,而不是在执行它时,它仍将变为{{ 1}}参考) - 谢谢@Rob

答案 2 :(得分:0)

在Swift中,声明一个闭包类型变量,并希望为其分配功能,以防止出现保留问题, 请按照以下步骤操作,全天搜索答案,并希望与他人分享:

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