如何找出所有闭包?解决未捕获self导致的强引用循环问题
这个问题我之前踩过不少坑——Swift里闭包默认会隐式捕获self(尤其是引用类型),偏偏编译器有时候不会及时抛出警告,结果就是一堆循环引用悄悄藏在代码里,排查起来特别麻烦。分享几个我亲测有效的方法,帮你精准找出所有这类闭包:
用Xcode正则查找精准定位
别直接搜in,那样结果太杂。Xcode的查找支持正则表达式,你可以用这个正则:\{[^\}]*in[^\}]*self
它会匹配所有包含self的闭包结构(闭包的基本格式是{ ... in ... }),还能自动过滤掉注释里的无关内容。记得在查找面板里勾选「Regular Expression」,再选择「Find in Project」就能扫遍整个项目。
如果要更精准地找完全没写捕获列表的闭包,可以用这个正则:^\s*\{[^\}\(]*in[^\}]*self,它会匹配那些开头没有[weak self]/[unowned self]的闭包,直接锁定需要修复的目标。触发Xcode静态分析工具
Xcode自带的静态分析能帮你找出潜在的循环引用,比字符串匹配更靠谱。操作很简单:- 顶部菜单选择
Product > Analyze(快捷键Shift + Command + B) - 分析完成后,在「Issue Navigator」里找「Potential leak of an object stored into 'xxx'」这类提示,大部分都是闭包隐式捕获
self导致的循环引用。
这个工具会真正分析代码的引用关系,不会漏过那些隐藏较深的问题。
- 顶部菜单选择
用SwiftLint强制规范闭包写法
如果想从根源上避免遗漏,可以用SwiftLint这个代码规范工具。它有现成的implicit_self规则,能强制你在闭包里显式写出self.,没写的话编译时直接报错提示。
只需要在项目的.swiftlint.yml配置文件里加上:opt_in_rules: - implicit_self这样每次编译都会自动检查所有闭包,从一开始就杜绝隐式捕获
self的情况,也就不用事后排查了。团队约定+代码审查兜底
对于团队协作的项目,可以提前约定:所有会被存储的闭包(比如网络请求回调、定时器闭包、UI控件的action闭包)必须显式添加捕获列表([weak self]或[unowned self])。在Code Review时,重点检查这类闭包,能快速发现遗漏的情况。
其实Swift在部分场景下会给出循环引用的警告,但确实存在不少边缘场景警告不会触发,所以还是得靠工具和规范来把好关。
内容的提问来源于stack exchange,提问作者Martin

