闭包中是否必须用guard let self?DispatchQueue.main需加[weak self]吗?
Swift闭包中self捕获的常见问题解答
闭包是异步流程里的常用工具,但不少开发者的写法其实没必要,先看两个典型例子:
异步加载数据的冗余写法
很多人会写这样的代码:
final class ViewController { private func bind() { self.viewModel.loadData { [weak self] in guard let self else { return } self.doSomething() } } }
但如果你的需求只是“self存在时才执行方法,不存在就跳过”,完全可以简化成:
self.viewModel.loadData { [weak self] in self?.doSomething() }
guard let self的作用是给外部的弱引用创建一个强引用,保证闭包执行期间self不会被释放,但如果只是单条方法调用,可选链已经能满足需求,没必要多这一层guard。
主队列异步的过度谨慎写法
还有开发者会这么处理主队列的异步闭包:
DispatchQueue.main.async { [weak self] in guard let self else { return } self.updateUI() }
但实际上DispatchQueue.main根本不会强持有任何对象,哪怕省略[weak self]也不会产生循环引用,直接这么写就完全没问题:
DispatchQueue.main.async { self.updateUI() }
接下来直接解答两个核心疑问:
疑问1:必须在所有闭包内用guard let self else { return }吗?
当然不用。要不要加这个guard完全看你的业务场景:
- 如果闭包里有好几处需要用到
self,用guard let self可以避免反复写self?,让代码更清爽; - 如果只是单条依赖
self的方法调用,用可选链self?.xxx()就足够,多写guard纯属冗余; - 核心原则:只有当你需要确保闭包执行期间
self不会被释放,或者想简化多段self相关代码时,才需要用guard let self,它不是所有闭包的标配写法。
疑问2:DispatchQueue.main的闭包里需要加[weak self]吗?
不需要。原因很直接:循环引用的前提是两个对象互相强持有,但self不会持有DispatchQueue,DispatchQueue也不会长期持有self——它只是临时持有闭包,闭包执行完毕就会释放self的引用,根本不会形成循环。
当然,如果你的闭包执行时间特别长,担心拖慢self的释放节奏,也可以考虑用[weak self],但这属于优化场景,不是必须的常规操作。
内容的提问来源于stack exchange,提问作者Frank
相关产品推荐
相关产品推荐

