NSTimer

一、NSTimer 运行条件

在一个NSRunloop 中的某个模式中运行,所在的runloop必须是运行的。

简单介绍Runloop:

一个线程对应一个runloop, 主线程runloop默认运行的,新建子线程runloop是未运行的,需要手动运行。

一个runloop包含的5个Mode:
  • kCFRynLoopDefaultMode:App的默认Mode,通常主线程是在这个Mode下运行
  • UITrackingRunLoopMode:界面跟踪Mode,用于ScrollView追踪触摸滑动,保证界面滑动时不受其他Mode影响
  • kCFRunLoopCommonModes:这是一个占位用的Mode,不是一种真正的Mode
  • UIInitializationRunLoopMode:在刚启动App时进入的第一个Mode,启动完成后不再使用
  • GSEventReceiveRunLoopMode:接受系统事件的内部Mode,通常用不到
如果Nstimer在当前runloop的DefaultMode,则当前runloop的触摸滑动会使其暂时停止运行,滑动结束后会继续运行。

二、NSTimer便利创建

当前线程, 自动加入当前runloop, 并以默认模式 NSDefaultRunLoopModel 运行.
runloop强引用timer, self强引用timer, timer强引用target: 而target通常是 self, 所以会存在强引用循环.
在销毁self之前,必须先手动的调用 invalidate方法将timer停止.虽然timer不会销毁,但此方法会将timer持有的target置nil.就不会强引用了.

self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timerFuction:) userInfo:@{@"a" : @"aaa"} repeats:YES];


//   timer调用的方法,注意对UI的操作如果不是主线程,需要切换到主线程
- (void)timerFuction:(NSTimer *)timer {
    NSDictionary *dic = (NSDictionary *)timer.userInfo;
    self.lab.text = [NSString stringWithFormat:@"%@:%@", [dic valueForKey:@"a"] ,[NSDate date]];
}

iOS10 开始的API
当前线程, 自动加入当前runloop, 并以默认模式 NSDefaultRunLoopModel 运行.
runloop强引用timer, self强引用timer, timer强引用block, 所以block内要弱引self,否则引用循环.

__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
        weakSelf.lab.text = [NSString stringWithFormat:@"%@", [NSDate date]];
    }];

三、NSTimer指定 Runloop 和 RunloopMode 创建

只创建了timer, 未添加到runloop的话不会运行. 但此时target如果是self的话,已经构成了强引用循环的犯罪事实.
运行条件: 将其加入到指定的runloop, 指定的runloop的模式,。
如果runloop的线程不是主线程, 还必须启动runloop才会运行.

self.timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(timerFuction:) userInfo:@{@"a" : @"aaa"} repeats:YES];
// 加入到当前runloop的默认模式. 此处为主线程,runloop是已经启动的
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];


// 如果是新创建的子线程,runloop是未启动的,就要手动启动runloop
dispatch_queue_t queue = dispatch_queue_create("somequeue", DISPATCH_CURRENT_QUEUE_LABEL);
dispatch_async(queue, ^{
    self.timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(timerFuction:) userInfo:@{@"a" : @"aaa"} repeats:YES];
    // 子线程的 runloop, 需要手动开启,因为是子线程的runloop,所以即使主线程在滚动,此时的timer也不会暂停的
    NSRunLoop *runloop = [NSRunLoop currentRunLoop];
    [runloop addTimer:self.timer forMode:NSDefaultRunLoopMode];
    [runloop run];
});


// timer 调用的方法
- (void)timerFuction:(NSTimer *)timer {
    NSDictionary *dic = (NSDictionary *)timer.userInfo;
    // 子线程trimer的方法,要回到主线程刷新UI
    dispatch_async(dispatch_get_main_queue(), ^{
        self.lab.text = [NSString stringWithFormat:@"%@:%@", [dic valueForKey:@"a"] ,[NSDate date]];
    });
}

Bloc的形式类似。

你可能感兴趣的:(NSTimer)