Swift调用API时是否需使用[weak self]?以Firebase注册场景为例
使用 [weak self] 处理延迟API调用的通用实践
你的场景分析
当你在RegisterViewController里调用Firebase创建用户API时,这个请求是异步执行的——后台完成后通过闭包回调结果。如果闭包直接引用self(比如执行self.performSegue(...)),闭包会强持有当前视图控制器实例。如果API请求延迟过久,或者用户在请求完成前就导航离开页面,本该被销毁的RegisterViewController会因为闭包的强引用滞留在内存中,造成内存泄漏。
什么时候必须用[weak self]?
核心判断标准:当闭包的生命周期可能超过持有它的对象(比如你的视图控制器)的生命周期时,必须使用[weak self]。
典型场景包括:
- 异步网络请求回调(Firebase、URLSession等)
- 定时器(Timer)的闭包
- 延迟执行的代码(
DispatchQueue.asyncAfter) - 任何可能在对象销毁后才触发的闭包
什么时候可以不用?
如果能确定闭包会在对象销毁前必然执行完毕,且闭包生命周期不会超过对象,就可以不用。比如:
- 同步执行的闭包(数组
map、filter等) - 视图控制器内部立即执行的短时长UI闭包(比如
UIView.animate,动画过程中视图控制器不会被销毁)
最佳实践总结
- 默认优先加[weak self]:对所有异步闭包先添加
[weak self],这是避免潜在内存泄漏最稳妥的做法,尤其适用于视图控制器这类生命周期受导航栈控制的对象。 - 用guard let转换强引用:拿到弱引用的self后,用
guard let self = self else { return }转换成强引用,既避免频繁解包可选值,也能保证只有视图控制器存在时才执行后续逻辑(比如segue跳转)。 - 警惕循环引用:如果闭包内还引用其他对象,要确保不会形成循环引用(比如self持有闭包,闭包又持有self)。
针对你的Firebase注册代码的修改示例
假设原代码如下:
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in if let error = error { // 处理错误 return } // 成功后跳转 self.performSegue(withIdentifier: "toHome", sender: self) }
修改为带[weak self]的安全版本:
Auth.auth().createUser(withEmail: email, password: password) { [weak self] authResult, error in guard let self = self else { return } // 确保视图控制器未被销毁 if let error = error { // 处理错误 return } // 安全执行跳转 self.performSegue(withIdentifier: "toHome", sender: self) }
这样修改后,即便用户在请求完成前离开页面,self会被正确释放;闭包执行时如果self已不存在,会直接返回,既避免内存泄漏,也防止了可能的崩溃。
内容的提问来源于stack exchange,提问作者nirneu
相关产品推荐
相关产品推荐

