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/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值