NSTimer

NSTimer的属性

+ @property(readonly, getter=isValid) BOOL valid :

返回Boolean 表示当前的timer是否还有效。

+ @property(copy) NSDate *fireDate :

定时器的触发时间。如果定时器已经无效,则返回最后一次的启动时间。也可以通过该属性来改变定时器的触发时间。

+ @property(readonly) NSTimeInterval timeInterval :

返回定时器的时间间隔。如果定时器的repeat为NO,则返回0。

+ @property(readonly, retain) id userInfo :

返回定时器的userInfo 对象,如果定时器已经失效,则无权访问,所以用之前,先通过valid 来检测定时器是否有效。

NSTimer的方法

类方法

1、以scheduled(安排)开头的方法,该类型方法创建的定时器,已经将定时器以默认的运行模式(NSDefaultRunLoopMode)安排到当前到run loop 中。即,表示不需要下面的方法手动将定时器加到run loop中。

- (void)addTimer:(NSTimer *)timer forMode:(NSRunLoopMode)mode;
  • 当创建后,repeat设为NO,则会在当前的NSDate,延迟interval后,执行一次。但是调用fire方法,则会立马执行。
  • repeat 设为YES,则每间隔interval,执行一次。
//interval表示时间间隔,
//repeats 表示是否重复执行,
//block中是定时器的执行代码。
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block;
//target 表示当前定时器启动时,接受aSelecttor消息的对象,并且定时器会对target 强引用,
//selector 表示定时器启动时发送给target的消息,
//userInfo 表示定时器的用户信息,同样会强引用,一般为nil,
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
//invocation 是NSInvocation类型,当定时启动时,通过该对象进行消息转发(调用某个对象的消息),同样也是强引用。
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;

2、需要手动加到runloop中,如果不加,不执行;调用fire方法则会执行一次,无论repeat是否为ture。

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;

实例方法

1、创建定时器,需要手动加到run loop中。

//date:定时器启动的时间。
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block;
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(id)ui repeats:(BOOL)rep;

2、

  • (void)fire:启动定时器的方法。
  • (void)invalidate :销毁定时器。

总结

  • 有block 的方法都是iOS10++ 才有,并且不存在循环引用的问题(已验证)。
  • 以scheduled 开头的方法,不需要手动将定时器加到runloop中,其他方法都需要。
  • 如果不加到run loop ,无论repeat是否为true ,都不会执行;调用fire ,只会执行一次,无内存泄漏的问题。

NSTimer的循环引用问题的本质是:

NSTimer在初始化的时候是放在VC方法中的,而VC的self又是作为NSTimer对象的一个参数存在的,就导致了一个死循环。

解决问题的本质:打破NSTimer对当前View的持有。

解决问题的方法:

1、调用invalidate方法,销毁定时器。切记:不可在VC的delloc方法中调用,循环引用不会走到delloc。
2、通过代理弱引用:

  • 创建middleWeak类,定义protocol,及弱引用delegate,定义timeAction方法,并在该方法中调用代理的方法;
  • 目标VC中,实现该代理,创建NStimer实例时,将target设为middleWeak,selector为timeAction。
  • 过程:定时器到执行middleWeak中的timeAction,然后回调目标VC的代理方法。

3、利用NSProxy消息转发

  • 创建middleNSProxy,实现methodSignatureForSelector 和 forwardInvocation,并创建weak修饰的id类型的target
  • 创建middleNSProxy实例,并将proxy的target设为self。
  • 将time的target设为middleNSproxy。
@interface ceshiProxy : NSProxy

@property (nonatomic, weak) id aTarget;      // 此对象要从外部传过来

@end

//.m
#import "ceshiProxy.h"

@implementation ceshiProxy

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.aTarget methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.aTarget];
}

@end

//使用
ceshiProxy *proxy = [ceshiProxy alloc];
proxy.aTarget = self; 
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:proxy selector:@selector(timerFire) userInfo:nil repeats:YES];

4、利用新的API
在iOS10以后,提供了三种新的API
scheduledTimerWithTimeInterval:repeats:block:
timerWithTimeInterval:repeats:block:
initWithFireDate:interval:repeats:block:

解决列表滑动,Timer不执行的问题:

[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
原因:当滑动ScrollView的时候,NSRunloop的mode并不是NSDefaultRunLoopMode,而是UITrackingRunLoopMode,为此,我们需要设置一个包含既包含NSDefaultRunLoopMode又包含UITrackingRunLoopMode的mode,那就是NSRunLoopCommonModes。

一位大神总结的Runloop知识点:https://blog.ibireme.com/2015/05/18/runloop/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容

  • 1. 什么是NSTimer   官方的解释“A timer provides a way to perform a...
    Timir阅读 784评论 0 3
  • NSTimer是iOS最常用的定时器工具之一,在使用的时候常常会遇到各种各样的问题,最常见的是内存泄漏,通常我们使...
    bomo阅读 1,205评论 0 7
  • 创建NSTimer 创建NSTimer的常用方法是: + (NSTimer *)scheduledTimerWit...
    LanWor阅读 1,370评论 0 2
  • 之前要做一个发送短信验证码的倒计时功能,打算用NSTimer来实现,做的过程中发现坑还是有不少的。 基本使用 NS...
    WeiHing阅读 4,383评论 1 8
  • 定时器: 需要被添加到Runloop,否则不会运行,当然添加的Runloop不存在也不会运行 还要指定添加到的Ru...
    Sunli_阅读 1,723评论 0 3