iOS NSTimer循环引用的几种解决办法
发布时间 - 2026-01-11 00:52:54 点击率:次发生场景

在 Controller B 中有一个 NSTimer
@property (strong, nonatomic) NSTimer *timer;
你创建了它,并挂载到 main runloop
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:true];
然后退出 Controller B 的时候,忘记关掉 timer 了
Controller B 将不会释放,B 与 timer 循环引用。因为创建 timer 的时候把 self 直接写进去了。
方法一
既然不能直接传 self,那传 weakSelf 试试
__weak typeof(self) weakSelf = self; self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:weakSelf selector:@selector(timerAction:) userInfo:nil repeats:true];
测试结果还是发生了循环引用,B 没有释放,timer 对 weakSelf 这个变量是强引用的,timer -> weakSelf -> B -> timer,三者之间形成循环引用。
方法二
设置一个包装类,包着 Controller B 放进 timer 中,像这样
我认为 Controller B 有几 MB 那么大,泄露了很浪费内存。
WeakWrap 只有几百个字节那么小,泄露了也没关系。
WeakWrap 中对 Controller B 弱引用,WeakWrap 包着 Controller B,传进 timer 中,就算忘记关 timer,也只是泄露了 WeakWrap 和 timer。
理论上还是有内存泄露,只不过比较少,如果一个 Controller 是频繁进出的,进出一次,丢失一个,如果有几十个泄露的 timer 挂在 main runloop 上会影响性能和流畅性,你想几十个 timer 一起 fire,又调用了 timer 事件响应方法,开销还是挺大的。
方法三
NSTimer 已知是会强引用参数 target:self 的了,如果忘记关 timer 的话,传什么进去都会被强引用。干脆实现一个 timer 算了,timer 的功能就是定时调某个方法,NSTimer 的调用时间是不精确的!它挂在 runloop 上受线程切换,上一个事件执行时间的影响。
利用 dispatch_asyn() 定时执行函数。看下面代码。
- (void)loop {
[self doSomething];
......
// 休息 time 秒,再调 loop,实现定时调用
[NSThread sleepForTimeInterval:time];
dispatch_async(self.runQueue, ^{
[weakSelf loop];
});
}
dispatch_async 中调 loop 不会产生递归调用
dispatch_async 是在队列中添加一个任务,由 GCD 去回调 [weakSelf loop]
这办法解决了timer 不能释放,挂在 runloop 不能移除的问题。
利用这方法,我写了个不会发生循环引用的 timer,controller 释放,timer 也自动停止释放,甚至 timer 的 block 里面可以直接写 self,也不会循环引用。github下载地址
方法四
NSTimer 我之前没遇到过循环引用的问题,因为我一直都是配对使用,在 viewWillAppear 开启,在 viewWillDisappear 关闭,不关闭的话那么多 timer 挂载在 runloop 上感觉挺影响性能和流畅性的,就像管理内存一样,申请和释放配对使用,就不会泄露了,谁申请谁释放的原则。但是很大的团队的话,别人可能会写错,造成泄露,可以从技术上,团队编程规范上解决他。
比如定一些规范,Controller 退出一定要成功销毁,不能泄露内存。Block 里不能写 self 等等。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# ios
# nstimer
# 循环引用
# nstimer的循环引用
# IOS开发代码分享之用nstimer实现倒计时功能
# iOS中的NSTimer定时器的初步使用解析
# IOS 中NSTimer定时器的使用
# iOS NSTimer循环引用的办法
# iOS如何巧妙解决NSTimer的循环引用详解
# 挂在
# 递归
# 几十个
# 流畅性
# 包着
# 都是
# 是在
# 就像
# 去了
# 是有
# 也没
# 下载地址
# 那么多
# 中有
# 执行时间
# 你想
# 我一直
# 我认为
# 可以直接
# 写了
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何在阿里云ECS服务器部署织梦CMS网站?
如何破解联通资金短缺导致的基站建设难题?
Laravel如何实现API资源集合?(Resource Collection教程)
网站制作大概要多少钱一个,做一个平台网站大概多少钱?
香港服务器租用每月最低只需15元?
悟空识字如何进行跟读录音_悟空识字开启麦克风权限与录音
如何快速搭建个人网站并优化SEO?
javascript基于原型链的继承及call和apply函数用法分析
Laravel如何使用查询构建器?(Query Builder高级用法)
Laravel如何实现数据库事务?(DB Facade示例)
如何快速辨别茅台真假?关键步骤解析
Laravel怎么自定义错误页面_Laravel修改404和500页面模板
如何在七牛云存储上搭建网站并设置自定义域名?
百度输入法ai组件怎么删除 百度输入法ai组件移除工具
Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】
大同网页,大同瑞慈医院官网?
Windows Hello人脸识别突然无法使用
如何在万网开始建站?分步指南解析
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】
Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程
如何快速完成中国万网建站详细流程?
Win11怎么设置默认图片查看器_Windows11照片应用关联设置
网站建设保证美观性,需要考虑的几点问题!
Laravel如何集成第三方登录_Laravel Socialite实现微信QQ微博登录
Laravel怎么使用artisan命令缓存配置和视图
Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】
详解jQuery中的事件
详解Nginx + Tomcat 反向代理 如何在高效的在一台服务器部署多个站点
如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)
C++时间戳转换成日期时间的步骤和示例代码
Laravel如何从数据库删除数据_Laravel destroy和delete方法区别
Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程
JavaScript如何实现类型判断_typeof和instanceof有什么区别
Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践
如何注册花生壳免费域名并搭建个人网站?
Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤
Laravel如何使用Gate和Policy进行权限控制_Laravel权限判定与策略规则配置
如何在IIS中新建站点并解决端口绑定冲突?
网站制作免费,什么网站能看正片电影?
PHP 500报错的快速解决方法
香港网站服务器数量如何影响SEO优化效果?
个人摄影网站制作流程,摄影爱好者都去什么网站?
武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?
Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区
如何使用 jQuery 正确渲染 Instagram 风格的标签列表
logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?
Laravel如何连接多个数据库_Laravel多数据库连接配置与切换教程
移动端脚本框架Hammer.js
Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程

