Xcode8调试黑科技(science and科技美学 technology):Memory Graph实战解决闭包引用循环难点

typealias Action = () -> Void

class MyView: UIView {

    var action: Action?

    init(action: @escaping Action) {
        self.action = action
        super.init(frame: CGRect.zero)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

小姑说再也不用担心引用循环啦!除非你是个瞎子。

那么如此写会发生引用循环呢?

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    var myView: MyView?

    override func viewDidLoad() {
        super.viewDidLoad()
        myView = MyView(action: testMethod)
    }

    func testMethod() {
        label.text = "haha"
    }

}

有了那几个图就很简单看出来了:myView保持了action,action保持了testMethod,testMethod中因为安装了vc的label所以也保持了VC。所以我们可以规定:方法中隐式的self的捕捉策略是strong。那样直白把办法传入子view中会引起引用循环。

小心到我们刚刚的靶子名:一个叫MyView,一个叫ViewController。大家pop了两回,按理说内存里不应该有那么些多个对象,可是依然有两份实例。所以,那之中引用循环了。点击肉色的叹号会油可是生Xcode分析出来的内存引用图形:

有不少叹号表明就有问题了。看内存中object的名字,有一条是Closure captures
leaked。展开后点击就可以看看这几个issue对应的内存图形体现在当中的面板中。
本来了,大家越多的时候是在debug页面下查看:

基本在那段代码上,一个类的点子里安装本身的特性,会捕捉那些特性吗?这几个地点可以写self,不过捕捉策略是unowned如故strong呢?
本条闭包的落实是不可能协调表明捕捉策略的:

这vc的view上有一个label控件,在viewDidLoad时开首化myView,并且将自家的一个testMethod方法用作参数传给了myView。
testMethod中安装了自身label的text。
留神,划重点了!

以此时候就进入了断点形式,可以查看issue面板,注意接纳右侧Runtime:

Xcode8的调试技能又增多了一个黑科学和技术:Memory
Graph。简而言之就是足以在运行时将内存中的靶子生成一张图。在现场的开发者听到了那么些音信时响起了雷鸣般的掌声!大家来探望前方记者发回的实地照片:

1.将逻辑完毕在一个匿名闭包里,不完成在类的法子上

那般就足以协调评释捕捉策略。那样的主意利用就和OC的block类似了:

        myView = MyView(){ [unowned self] in
            self.label.text = "haha"
        }

跟着大家在一个ViewController中初阶化MyView,并且也保留为属性:

2.在匿名闭包中调用方法

不是直接传入testMethod方法,而是在传出的闭包中调用自身的办法:

        myView = MyView(){ [unowned self] in
            self.testMethod()
        }

欢迎关切自身的今日头条:@没故事的卓同学

连带链接:
WWDC 2016 Session 410 Visual Debugging with
Xcode

科技美学,那边浮现了swift函数式的特征:函数可以轻易的作为一个变量传递。

    func testMethod() {
        label.text = "haha"
    }

于是就来证爱他美下。运行起来后,push那些ViewController后pop出去(记得要开展五次,好像唯有五次Xcode有时不会启动分析)。
继之点击那一个按钮:

这么些事例影射里开发中一个大面积的景观:一个tableViewCell中有一个刨除按钮,通过闭包将艺术传进去,cell保存那些闭包;另一方面那几个闭包被调起后,删除某条数据后刷新数据源。

缓解方案

那就是说通过一个实际项目来陶冶一下吧。
首先大家写了一个自定义UIView:MyView。早先化的时候接受一个从未参数也从未重回值的闭包作为参数,并存为投机的属性: