iOS 中的 timer 任务(寻找内存恶鬼之旅)
前言
在 iOS
的开发过程中定时任务中能找到使用的场景,然而在 iOS
中默认的有关 timer
的 api
总是那么晦涩难用,而且暗坑不断,一旦遇上,会让你一脸懵逼,为了不再同一个地方跌倒两次,我决心花些时间做一篇总结,也用以提醒读者,谨慎使用。 之前在做一个空白页的计时器的时候使用到了 CADisplayLink
,这货把我坑惨了, 循环引用导致内存随着时间的增加而上升,短时间使用没啥感觉,要不是使用工具这是很难发现的。
分析
通常,在解决循环引用的时候我们会引入 weak
, 通过 weak
修饰打破循环引用中的 环
, 如:
@property (nonatomic, weak) CADisplayLink *link;self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(fireAction)];[self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
复制代码
然而,这样做 link
直接不工作了, 因为 link
没有别的地方引用,当它初始化完成立即就被释放掉了 。那么换一种思路呢?
__weak typeof(self) weakSelf = self;self.link = [CADisplayLink displayLinkWithTarget:weakSelf selector:@selector(fireAction)];[self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
复制代码
这样做也是徒劳的,当 self.link
持有 weakSelf
时也就是持有了 self
, 而 link
是通过 target
强持有的 self
所以还是无法打破形成的环,我们通过 Memory Graph
就可以检测是否内存图关系:
这是 RunLoop
与 Timer
的内存关系,再看看 Timer
与 target
的关系:
方案
既然这个环用常规的方法无法打破,那该怎么办呢? 这时候 NSProxy
就可也发挥它的长处了。我们实现一个 NSProxy
的子类 WeakProxy
,WeakProxy
弱引用一个 target
,然后在通过 WeakProxy
消息转发到 target
从而达到破除循环的效果:
- (id)forwardingTargetForSelector:(SEL)selector {return _target;
}- (void)forwardInvocation:(NSInvocation *)invocation {void *null = NULL;[invocation setReturnValue:&null];
}- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {return [NSObject instanceMethodSignatureForSelector:@selector(init)];
}
复制代码
proxy
弱引用的 target
所以不影响 target
的正常释放,当 target
释放后,link
引用计数减一 link
释放,proxy
引用计数减一也会释放,因此,原来的环不在了,完美解决了相互引用的问题。
源码 Demo
iOS 中的 timer 任务(寻找内存恶鬼之旅)相关推荐
- iOS中滤镜处理及相关内存泄漏问题的解决
iOS中滤镜处理及相关内存泄漏问题的解决 参考文章: (1)iOS中滤镜处理及相关内存泄漏问题的解决 (2)https://www.cnblogs.com/ToBeTheOne/p/5708906.h ...
- iOS中内存管理的问题——堆和栈
计算机系统中,运行的应用程序的数据都是保存在内存中的,不同类型的数据,保存的内存区域不同: 1)栈区(stack)由编译器自动分配并释放,一般保存函数的参数值.局部变量 2)堆区(heap)由程序员分 ...
- (转载)深入了解iOS中的OOM(低内存崩溃)
英文原文:https://programmer.ink/think/learn-more-about-oom-low-memory-crash-in-ios.html 中文翻译:https://www ...
- 深入了解iOS中的OOM(低内存崩溃)
在iOS开发过程或者用户反馈中,可能会经常看到这样的情况,用着用着就崩溃了,而在后台查看崩溃栈的时候,找不到崩溃日志.其实这大多数的可能是系统产生了低内存崩溃,也就是OOM(还有一种可能是主线程卡死, ...
- iOS中引用计数内存管理机制分析
在 iOS 中引用计数是内存的管理方式,虽然在 iOS5 版本中,已经支持了自动引用计数管理模式,但理解它的运行方式有助于我们了解程序的运行原理,有助于 debug 程序. 操作系统的内存管理分成堆和 ...
- 【iOS系列】-iOS中内存管理
iOS中创建对象的步骤: 1,分配内存空间,存储对象 2,初始化成员变量 3,返回对象的指针地址 第一:非ARC机制: 1,对象在创建完成的同时,内部会自动创建一个引用计数器,是系统用来判断是否回收对 ...
- iOS中关于NSTimer使用知多少
看到这个标题,你可能会想NSTimer不就是计时器吗,谁不会用,不就是一个能够定时的完成任务的东西吗? 我想说你知道NSTimer会retain你添加调用方法的对象吗?你知道NSTimer是要加到ru ...
- ios 中的小技巧 - 总有你想要的 一
UITableView的Group样式下顶部空白处理 在viewWillAppear里面添加如下代码: //分组列表头部空白处理 CGRect frame = myTableView.tableHea ...
- 内存恶鬼drawRect
转载于:http://bihongbo.com/ 内存恶鬼drawRect 标题有点吓人,但是对于drawRect的评价倒是一点都不过分.在平日的开发中,随意覆盖drawRect方法,稍有 ...
最新文章
- 2022中国人工智能芯片行业研究报告
- 《天天数学》连载43:二月十二日
- 事件相互独立的几种不同说法
- Java final关键字详解
- 小美赛(认证杯)ABCD题翻译
- 远程桌面 无法打开连接文件default.rdp
- MySQL卸载不干净-MySQL Connector Net xxx文件怎么也删除不了?一招解决它
- wordpress入门主题_WordPress播客入门指南
- 臭氧9母带处理工具:iZotope Ozone 9 Advanced for Mac
- stm32f103读取红外接收HS0038A2
- vm连接服务器桌面,Vmware之使用Windows自带的远程桌面连接
- 人员属性识别 PETA数据集下载
- 后端开发工程师不懂这些就危险了
- win32-c语言实现俄罗斯方块
- 基于Redis的incr、发布订阅防并发和setnx、轮询防并发的理解
- LQ0270 手机尾数【水题】
- 实现html页面的倒计时
- Java实现微信小程序支付(支付,提现,退款)
- 扒一扒DDR4的新功能和PCB设计上的一些注意事项--转
- wannafly summer camp day6
热门文章
- 大专找不到计算机工作吗,大专毕业就没工作?
- AWS的“炮仗”与Serverless
- python爬取的图片无法显示的问题
- S2-045 Struts 2漏洞(CVE-2017-5638) 实战
- 如何转潜在客户为客户?
- 怎么样挑选关键才才能让网站优化效果超凡出众
- 5月12日 疯狂猜成语反省总结站立会议-----赵静娜,尹亚男,胡潇丹,郭林林,袁雪,杨霏...
- python 写数值模拟器_python实现模拟器爬取抖音评论数据的示例代码
- python request url编码_Python爬虫进阶——Request对象之Get请求与URL编码【英雄联盟吧】...
- ERTMS架构及UIC对高速铁路的描述