NSTimer深入理解
NSTimer,即计时器,用于定时执行一些任务,一次或者多次。
系统Foundation框架提供的最常用方法如下,创建一个NSTimer,并将它放到当前runloop的default mode中。
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti // 执行任务的时间间隔
target:(id)aTarget // 执行任务的对象
selector:(SEL)aSelector // 执行任务的对象方法
userInfo:(nullable id)userInfo // 用于传一些参数
repeats:(BOOL)yesOrNo; // 是否重复执行
1、怎么保证在未来某个时间点,要执行任务时,target还有效呢?target完全有可能被释放了呀。鉴于此,NSTimer会持有target对象,直到NSTimer invalidate。不同的是,一次性NSTimer会在执行完任务之后,会自动invalidate;而重复性NSTimer,则需要手动invalidate,否则会造成内存泄漏。
2、由于NSTimer会持有target对象,如果刚好target对象就是self,而NSTimer又是self的一个实例变量,就会引发循环引用:self->NSTimer->self。
@interface TimerTest () {
NSTimer *_timer; // self持有_timer
} @end @implementation TimerTest - (id)init
{
if (self = [super init]) {
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(test) userInfo:nil repeats:YES]; // _timer持有self
}
return self;
} - (void)dealloc
{
// 因为_timer持有self,所以self的引用计数>=1,也就执行不到dealloc。
[_timer invalidate]; // 而执行不到dealloc,这句也就执行不到,_timer会一直持有self。这时候只能其他地方将_timer invalidate才行。
} - (void)test
{ } @end
为了解决这种循环引用问题,主要有两种方法:
1)实现一个NSTimer的category,并提供block接口。
@implementation NSTimer (Safe) + (NSTimer *)safeScheduledTimerWithTimeInterval:(NSTimeInterval)interval
repeats:(BOOL)repeats
blk:(void(^)())blk {
return [self scheduledTimerWithTimeInterval:interval
target:self // target变成了NSTimer类对象,类对象由系统自动回收
selector:@selector(_doBlock:) // NSTimer会把自己传过去
userInfo:[blk copy] // 把block拷贝到堆上,避免栈block到用时已经被回收了
repeats:repeats];
} + (void)_doBlock:(NSTimer *)timer {
void(^blk)() = timer.userInfo;
if(blk) {
blk();
}
} @end @interface TimerTest () {
NSTimer *_timer; // self持有_timer
} @end @implementation TimerTest - (id)init
{
if (self = [super init]) {
__weak TimerTest *weakSelf = self;
_timer = [NSTimer safeScheduledTimerWithTimeInterval: repeats:YES blk:^{
__strong TimerTest *strongSelf = weakSelf;
[strongSelf test];
}];
}
return self;
} - (void)dealloc
{
[_timer invalidate];
} - (void)test
{ } @end
3、NSTimer必须放在runloop中才能生效。如下方法就只是创建一个NSTimer,而并没有把它放到runloop中。
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(nullable id)userInfo
repeats:(BOOL)yesOrNo;
需要调用如下方法把它放到runloop中,才能生效。
- (void)addTimer:(NSTimer *)timer forMode:(NSRunLoopMode)mode;
https://developer.apple.com/documentation/foundation/nstimer/2091889-scheduledtimerwithtimeinterval
NSTimer深入理解的更多相关文章
- iOS开发中深入理解CADisplayLink和NSTimer
一.什么是CADisplayLink 简单地说,它就是一个定时器,每隔几毫秒刷新一次屏幕. CADisplayLink是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器.我们在应用中创建一 ...
- 关于NSRunLoop和NSTimer的深入理解
一.什么是NSRunLoop NSRunLoop是消息机制的处理模式 NSRunLoop的作用在于有事情做的时候使的当前NSRunLoop的线程工作,没有事情做让当前NSRunLoop的线程休眠 NS ...
- 深入理解CADisplayLink和NSTimer
一.什么是CADisplayLink 简单地说,它就是一个定时器,每隔几毫秒刷新一次屏幕. CADisplayLink是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器.我们在应用中创建一 ...
- 深入理解RunLoop
网上看的一篇文章,写的真好,我得多看几次好好理解理解 膜拜大神,转载至此便于学习查看. 此处标明原文链接:http://blog.ibireme.com/2015/05/18/runloop/ ...
- iOS开发——高级篇——iOS 中的 NSTimer
以前的老代码在使用 NSTimer 时出现了内存泄露 NSTimer fire 我们先用 NSTimer 来做个简单的计时器,每隔5秒钟在控制台输出 Fire .比较想当然的做法是这样的: 1 2 3 ...
- __block 与 __weak的区别理解
Blocks理解: Blocks可以访问局部变量,但是不能修改 如果修改局部变量,需要加__block __block int multiplier = 7; int (^myBlock)(int) ...
- Swift: 深入理解Core Animation(一)
如果想在底层做一些改变,想实现一些特别的动画,这时除了学习Core Animation之外,别无选择. 最近在看<iOS Core Animation:Advanced Techniques&g ...
- RunLoop机制理解
一.浅识RunLoop RunLoop在开发中我们一直在用,但是没有注意他.要想理解RunLoop,首先我们需要先了解一下程序运行机制. 程序运行机制:我们都知道OC是运行时语言,也就是说对象的类型是 ...
- IOS开发中NSRunloop跟NSTimer的问题
在Windows时代,大家肯定对SendMessage,PostMessage,GetMessage有所了解,这些都是windows中的消息处理函数,那对应在ios中是什么呢,其实就是NSRunloo ...
随机推荐
- java-两个整数变量的交换-不需要定义第三方变量
代码如下: class Example { public static void main(String[] args) { /* * 位异或运算符的特点 * ^的特点:一个数据对另一个数据位异或两次 ...
- docker 搭建maven 私服
# 搜索镜像 docker search nexus; #拉取nexus镜像docker pull sonatype/nexus; #运行 -id 创建守护式容器--privileged=true 授 ...
- loadrunner 运行脚本-Run-time Settings-ContentCheck简单设置
运行脚本-Run-time Settings-ContentCheck简单设置 by:授客 QQ:1033553122 ContentCheck的设置可用来让VuGen检测存在错误的站点页面.如果被测 ...
- Kotlin入门(5)字符串及其格式化
上一篇文章介绍了数组的声明和操作,包括字符串数组的用法.注意到Kotlin的字符串类也叫String,那么String在Java和Kotlin中的用法有哪些差异呢?这便是本文所要阐述的内容了. 首先要 ...
- (网页)JS编程中,有时需要在一个方法返回两个个或两个以上的数据
转自脚本之家: 1 使用数组的方式,如下: <html> <head> <title>JS函数返回多个值</title> </head> & ...
- C#基础(数据类型运算符)
---恢复内容开始--- 1.类 修饰符 class 类名 基类或接口 { } 2.命名规范 成员变量前加_ 首字符小写,后面单词首字母大写(Camel规则) 接口首字母为I 方法的命名使用动词 所有 ...
- input输入的数据只允许整数和浮点型数据
//第一步:引入jquery //第二步:input输入框绑定该函数 例如:<input type="text" name="price" onInput ...
- Python实例---模拟微信网页登录(day3)
第四步: 扫码成功后获取最近联系人信息---day3代码 settings.py """ Django settings for weixin project. Gene ...
- Dos命令讲解
目录 一.什么是DOS 二.启动DOS的多种方法 三.DOS的内部命令与外部命令 四.系统环境变量讲解 增加Path环境变量路径 常见的系统环境变量 五.常用的运行命令 六.DOS使用技巧 设置CMD ...
- Qt实现同步(阻塞式)http get等网络访问操作
Qt的网络操作类是异步(非阻塞的),但有时想做一些阻塞的事情就不方便了,可用如下几行代码轻松实现: QByteArray MyNetworkAccess::get(const QString & ...