利用Xcode内存图工具分析解决App循环引用一例

在调试App时打开Xcode内存图工具,发现有循环引用


这里写图片描述

由上图可得:

SectionTrace对象->SectionDayTracesGroupHeader对象->通过闭包ignore.context->SectionTrace对象

同样有

SectionTrace对象->SectionDayTracesGroupHeader对象->通过闭包evaluate.context->SectionTrace对象

即SectionTrace和SectionDayTracesGroupHeader对象被2条线牢牢锁住,无法被释放!

打开SectionDayTracesGroupHeader类,看一下

class SectionDayTracesGroupHeader:HeaderFooterViewRepresentable{
    typealias HandleType = (Date)->()
    //忽略、评定按钮的回调
    var ignoreHandle:HandleType?
    var evaluateHandle:HandleType?
}

那么它们是在哪里被赋值的呢?

答案是在我的某一个VC里,因为evaluate闭包实现比较复杂所以只看ignore闭包:

///返回指定Section的忽略处理闭包
private func getIgnoreHandleWith(section:Section)->(Date)->(){
    return {date in
        if let idx = section.index{
            //TODO:只是本次删除,下次还会显示
            self.form.remove(at: idx)
        }
    }
}

注意传入的参数section,它是从哪里来呢?

是在Section被创建的时候:

let section = SectionTrace("\(day.dateString)"){section in
    //省略无关代码...
    header.evaluateHandle = getEvaluateHandleWith(section: section)
    header.ignoreHandle = getIgnoreHandleWith(section: section)
    section.header = header
}

OK!很清楚了,我们犯的错误是:

将section通过参数传给了header的闭包,导致header拥有section;而section随后又去拥有header.

我们需要打破其中一条链路:

private func getIgnoreHandleWith(section:Section)->(Date)->(){
    return {[unowned self,unowned section]date in
        if let idx = section.index{
            //TODO:只是本次删除,下次还会显示
            self.form.remove(at: idx)
        }
    }
}

如上代码,我们将闭包中的section替换为弱引用,所以上面的引用循环不复存在:


这里写图片描述

可见,原来的双线锁死已变为单线串联,一切都变的很美好了 ;)

猜你喜欢

转载自blog.csdn.net/mydo/article/details/81254151