美文网首页
定时器、RunLoop、多线程

定时器、RunLoop、多线程

作者: huoshe2019 | 来源:发表于2019-10-08 10:59 被阅读0次

前言

这里主要分析定时器与RunLoop、多线程之间的关系以及易错点。
定时器包含以下几部分:

  • NSTimer
  • CADisplayLink
  • GCD
  • performSelector:afterDelay

小注:

  • 上面的定时器除了GCD,其它都是基于RunLoop的,也就是说如果在子线程(默认不开启RunLoop),所有定时器方法都不会执行的。
  • GCD定时器精确到纳秒
  • GCD并不运行在RunLoop中
  • RunLoop底层采用GCD定时器

一、NSTimer

1.1、自动加入当前的RunLoop、模式是default mode。

但是子线程中,需要手动创建runloop,并进行创建

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

1.2、不会自动加入RunLoop、需要手动addTimer:forMode

  • timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block;
  • timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
  • timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
  • initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(id)ui repeats:(BOOL)rep;
  • initWithFireDate:(NSDate *)date interval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block;

易错题:

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        //不会执行
        [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
        //添加这句、可以正常执行
        //必须在下面,因为不添加Source,不会正常开启RunLoop
        [[NSRunLoop currentRunLoop] run];
    });

二、CADisplayLink

这里需要手动加入RunLoop

// 创建CADisplayLink
CADisplayLink *disLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkMethod)];
//触发间隔
disLink.frameInterval = 2;
// 添加至RunLoop中
[disLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
// 终止定时器
[disLink invalidate];
// 销毁对象
disLink = nil;

三、GCD

/** 创建定时器对象
 * para1: DISPATCH_SOURCE_TYPE_TIMER 为定时器类型
 * para2-3: 中间两个参数对定时器无用
 * para4: 最后为在什么调度队列中使用
 */
_gcdTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
/** 设置定时器
 * para2: 任务开始时间
 * para3: 任务的间隔
 * para4: 可接受的误差时间,设置0即不允许出现误差
 * Tips: 单位均为纳秒
 */
dispatch_source_set_timer(_gcdTimer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
/** 设置定时器任务
 * 可以通过block方式
 * 也可以通过C函数方式
 */
dispatch_source_set_event_handler(_gcdTimer, ^{
    static int gcdIdx = 0;
    NSLog(@"GCD Method: %d", gcdIdx++);
    NSLog(@"%@", [NSThread currentThread]);
    
    if(gcdIdx == 5) {
        // 终止定时器
        dispatch_suspend(_gcdTimer);
    }
});
// 启动任务,GCD计时器创建后需要手动启动
dispatch_resume(_gcdTimer);

备注:
GCD不依赖RunLoop

四、performSelector:afterDelay

4.1、概念

  • 是消息传递的一种方式
  • 不需要编译的时候声明这些方法,是运行时

4.2、相关方法

4.2.1、同步执行、在任何线程正常执行(不受RunLoop影响)

  • (id)performSelector:(SEL)aSelector;
  • (id)performSelector:(SEL)aSelector withObject:(id)object;
  • (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

4.2.2、异步执行、只在主线程执行(RunLoop影响)

原因就是子线程RunLoop默认不开启,定时器必须加入RunLoop才能正常执行。

  • (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray * )modes;
  • (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;

4.2.3、主线程(waitUntilDone决定是否阻塞主线程)(不受RunLoop影响)

  • (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray * )array;
  • (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;

4.2.4、主线程和子线程(waitUntilDone决定是否阻塞主线程)(不受RunLoop影响)

  • (void)performSelector:(SEL)aSelector onThread:(NSThread * )thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray * )array;
  • (void)performSelector:(SEL)aSelector onThread:(NSThread * )thr withObject:(id)arg waitUntilDone:(BOOL)wait;

总结:

1、不受Runloop、子线程影响,可以正常使用的
GCD
2、不受Runloop、受子线程影响(需要手动启动Runloop)
NSTimer➡️scheduledTimer...方法
3、受Runloop、受子线程影响(需要手动加入Runloop、需要手动启动)
NSTimer➡️除了scheduledTimer...方法
CADisplayLink
performSelector: afterDelay:

相关文章

  • 2022-09-20

    Runloop runtime kvo kvo多线程sdwebimage afnetwork底层原理内存管理定时器...

  • 定时器、RunLoop、多线程

    前言 这里主要分析定时器与RunLoop、多线程之间的关系以及易错点。定时器包含以下几部分: NSTimer CA...

  • iOS三大定时器:NSTimer、CADisplayLink、G

    一、介绍NSTimer:基于Runloop实现的定时器CADisplayLink:基于Runloop实现的定时器,...

  • iOS-Runloop常驻线程/性能优化

    主要聊聊以下内容 1 Runloop基本概要2 Runloop与定时器3 Runloop常驻线程4 Runloop...

  • RunLoop

    1、 Runloop 2、RunLoop与线程 3、RunLoop相关类 4、GCD中的定时器 5、CFRunLo...

  • GCD定时器的实现

    GCD定时器 GCD定时器不受RunLoop约束,比NSTimer更加准时 证明,实现GCD定时器

  • 运行循环 RunLoop

    观察RunLoop的活动阶段 定时器 图片加载 线程常驻 CD定时器

  • GCD定时器

    GCD定时器 GCD定时器不受RunLoop的影响,调用频率比较固定

  • GCD创建定时器和NSTimer定时器

    NSTimer定时器不准,因为scheduleTimer放在runloop里面,受runloop模式影响会不准,可...

  • NSTimer到底准不准?

    1、RunLoop的影响 原因分析: 定时器被添加在主线程中,由于定时器在一个RunLoop中被检测一次,所以如果...

网友评论

      本文标题:定时器、RunLoop、多线程

      本文链接:https://www.haomeiwen.com/subject/echfuctx.html