当前位置: 移动技术网 > IT编程>移动开发>IOS > iOS学习笔记-137.RunLoop05——Runloop相关类3_CFRunLoopTimerRef(NSTimer)为何定时有时会失败

iOS学习笔记-137.RunLoop05——Runloop相关类3_CFRunLoopTimerRef(NSTimer)为何定时有时会失败

2018年10月13日  | 移动技术网IT编程  | 我要评论

郭伯雄 维基百科,信知生男恶,真假茱丽叶

ios学习笔记-137.runloop05——runloop相关类3_cfrunlooptimerref(nstimer)为何定时有时会失败。

一、cfrunlooptimerref 主要说明

cfrunlooptimerref是基于时间的触发器

基本上说的就是nstimer,它会受到runloop的mode的影响

gcd的定时器不受runloop的mode的影响


二、nstimer定时器不能用了问题演示

2.1 nstimer定时器不能用了,图示

image

2.2 nstimer定时器不能用了代码示例1

-(void)timer1{
    //该方法内部自动添加到runloop中,并且设置运行模式为默认
    nstimer *timer = [nstimer scheduledtimerwithtimeinterval:1.0 target:self selector:@selector(run) userinfo:nil repeats:yes];
}

2.3 nstimer定时器不能用了代码示例2

我们首先在主线程上创建一个定时器,并且把它添加到默认模式下。

-(void)timer2{
    //创建定时器
    nstimer *timer = [nstimer timerwithtimeinterval:1.0 target:self selector:@selector(run) userinfo:nil repeats:yes];

    //2.添加定时器到runloop中,指定runloop的运行模式为nsdefaultrunloopmode
     /*
        第一个参数:定时器
        第二个参数:runloop的运行模式
       */
    [[nsrunloop mainrunloop] addtimer:timer formode:nsdefaultrunloopmode];
}

三、nstimer定时器不能用了解决方式

3.1 问题分析与解决方式说明

由前面的学习,我们知道,当我们的 uitextview 滚动的时候,我们主线程的运行模式是 uitrackingrunloopmode。然而我们的定时器是添加在 nsdefaultrunloopmode,模式下。它能再 uitrackingrunloopmode下运行,那不就见鬼了吗?

说了这么多?那么我们的解决方式也就是来了,我们把定时器在添加到 uitrackingrunloopmode 模式下,不就ok了吗?。除此之外,我们还可以把它添加到 nsrunloopcommonmodes模式下,因为 nsrunloopcommonmodes = nsdefaultrunloopmode + uitrackingrunloopmode


3.2 针对 2.2 中的解决方式1

-(void)timer1{
    //该方法内部自动添加到runloop中,并且设置运行模式为默认
    nstimer *timer = [nstimer scheduledtimerwithtimeinterval:1.0 target:self selector:@selector(run) userinfo:nil repeats:yes];
    //可以通过如下来修改它的运行模式
    [[nsrunloop currentrunloop] addtimer:timer formode:uitrackingrunloopmode];
}

3.3 针对 2.2 中的解决方式2

推荐这种

-(void)timer1{
    //该方法内部自动添加到runloop中,并且设置运行模式为默认
    nstimer *timer = [nstimer scheduledtimerwithtimeinterval:1.0 target:self selector:@selector(run) userinfo:nil repeats:yes];
    //可以通过如下来修改它的运行模式
    [[nsrunloop currentrunloop] addtimer:timer formode:nsrunloopcommonmodes];
}

3.4 针对 2.3 中的解决方式1

-(void)timer2{
    //创建定时器
    nstimer *timer = [nstimer timerwithtimeinterval:1.0 target:self selector:@selector(run) userinfo:nil repeats:yes];

    //2.添加定时器到runloop中,指定runloop的运行模式为nsdefaultrunloopmode
     /*
        第一个参数:定时器
        第二个参数:runloop的运行模式
       */
    [[nsrunloop mainrunloop] addtimer:timer formode:nsdefaultrunloopmode];

    // 3.1 第一种方式,再把它添加到 uitrackingrunloopmode
    [[nsrunloop mainrunloop] addtimer:timer formode:uitrackingrunloopmode];
}

3.5 针对 2.3 中的解决方式2

推荐这种

-(void)timer2{
    //创建定时器
    nstimer *timer = [nstimer timerwithtimeinterval:1.0 target:self selector:@selector(run) userinfo:nil repeats:yes];

    //nsrunloopcommonmodes = nsdefaultrunloopmode + uitrackingrunloopmode
    //占用,标签,凡是添加到nsrunloopcommonmodes中的事件 都会被同时添加到打上commmon标签的运行模式上
    [[nsrunloop mainrunloop] addtimer:timer formode:nsrunloopcommonmodes];
}

四、子线程中使用 nstimer 定时器

4.1 子线程中不能运行 nstimer 定时器?

我们创建了如下代码,

-(void)viewdidload{
    [nsthread detachnewthreadselector:@selector(timer3) totarget:self withobject:nil];
}

-(void)timer3{ 
    //创建一个定时器
    //该方法内部自动添加到runloop中,并且设置运行模式为默认
    [nstimer scheduledtimerwithtimeinterval:1.0 target:self selector:@selector(run) userinfo:nil repeats:yes];
}

我们发现,我们的定时器,不能工作了?那么怎么解决呢?

4.2 问题分析月解决方式说明

分析上面的问题,我们知道,nstimer是需要 runloop 的。之前我们在主线程中运行创建nstimer的时候,不需要自己手动来获取runloop那是因为,主线程中的 runloop 已经自动创建了。然而子线程中的 runloop 是需要我们手动创建的。而创建的方法就是调用 currentrunloop 方法,如实我们就有了解决方案,就是自己创建 runloop 并且运行它。

4.3 解决示例代码

于是针对上面的代码,我们就有了下面的解决代码

-(void)timer3{
    //子线程中,默认是没有创建 runloop 的,可以通过 [nsrunloop currentrunloop] 来创建,它其实是一个懒加载
    nsrunloop *currentrunloop = [nsrunloop currentrunloop];

    //创建一个定时器
    //该方法内部自动添加到runloop中,并且设置运行模式为默认
    [nstimer scheduledtimerwithtimeinterval:1.0 target:self selector:@selector(run) userinfo:nil repeats:yes];

    //让 runloop 运行
    [currentrunloop run];
}

除此之外,我们上面scheduledtimerwithtimeinterval,该方法内部自动添加到runloop中,并且设置运行模式为默认,它内部其实已经调用了[nsrunloop currentrunloop]。那么我们直接运行就行了。于是又有

-(void)timer3{
    //创建一个定时器
    //该方法内部自动添加到runloop中,并且设置运行模式为默认。那么我们可以知道,它内部其实已经调用了[nsrunloop currentrunloop]
    [nstimer scheduledtimerwithtimeinterval:1.0 target:self selector:@selector(run) userinfo:nil repeats:yes];

    [[nsrunloop currentrunloop] run];
}

五、gcd定时器——不受runloop的mode的影响

nstimer 会受到 runloop的mode的影响。然而gcd不会。

5.1 gcd定时器的使用。


-(void)gcdtimer{
    nslog(@"%s",__func__);
   //1.创建gcd中的定时器
   /*
     第一个参数:source的类型dispatch_source_type_timer 表示是定时器
     第二个参数:描述信息,线程id
     第三个参数:更详细的描述信息
     第四个参数:队列,决定gcd定时器中的任务在哪个线程中执行
     */
    dispatch_source_t timer = dispatch_source_create(dispatch_source_type_timer, 0, 0, dispatch_get_global_queue(0, 0));

    //2.设置定时器(起始时间|间隔时间|精准度)
    /*
       第一个参数:定时器对象
       第二个参数:起始时间,dispatch_time_now 从现在开始计时
       第三个参数:间隔时间 1.0 gcd中时间单位为纳秒
       第四个参数:精准度 绝对精准0
       */
    dispatch_source_set_timer(timer, dispatch_time_now, 1.0 * nsec_per_sec, 0 * nsec_per_sec);

    //3.设置定时器执行的任务
    dispatch_source_set_event_handler(timer, ^{
        nslog(@"gcd---%@",[nsthread currentthread]);
    });

    //4.启动执行
    dispatch_resume(timer);
    self.timer = timer;
}

5.2 gcd定时器补充


dispatch_source_type_timer         定时响应(定时器事件)
dispatch_source_type_signal        接收到unix信号时响应

dispatch_source_type_read          io操作,如对文件的操作、socket操作的读响应
dispatch_source_type_write         io操作,如对文件的操作、socket操作的写响应
dispatch_source_type_vnode         文件状态监听,文件被删除、移动、重命名
dispatch_source_type_proc         进程监听,如进程的退出、创建一个或更多的子线程、进程收到unix信号

下面两个都属于mach相关事件响应
    dispatch_source_type_mach_send
    dispatch_source_type_mach_recv

下面两个都属于自定义的事件,并且也是有自己来触发
    dispatch_source_type_data_add
    dispatch_source_type_data_or

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

  • ios uicollectionview实现横向滚动

    现在使用卡片效果的app很多,之前公司让实现一种卡片效果,就写了一篇关于实现卡片的文章。文章最后附有demo实现上我选择了使用uicollectionview ... [阅读全文]
  • iOS UICollectionView实现横向滑动

    本文实例为大家分享了ios uicollectionview实现横向滑动的具体代码,供大家参考,具体内容如下uicollectionview的横向滚动,目前我使... [阅读全文]
  • iOS13适配深色模式(Dark Mode)的实现

    iOS13适配深色模式(Dark Mode)的实现

    好像大概也许是一年前, mac os系统发布了深色模式外观, 看着挺刺激, 时至今日用着也还挺爽的终于, 随着iphone11等新手机的发售, ios 13系统... [阅读全文]
  • ios 使用xcode11 新建项目工程的步骤详解

    ios 使用xcode11 新建项目工程的步骤详解

    xcode11新建项目工程,新增了scenedelegate这个类,转而将原appdelegate负责的对ui生命周期的处理担子接了过来。故此可以理解为:ios... [阅读全文]
  • iOS实现转盘效果

    本文实例为大家分享了ios实现转盘效果的具体代码,供大家参考,具体内容如下demo下载地址: ios转盘效果功能:实现了常用的ios转盘效果,轮盘抽奖效果的实现... [阅读全文]
  • iOS开发实现转盘功能

    本文实例为大家分享了ios实现转盘功能的具体代码,供大家参考,具体内容如下今天给同学们讲解一下一个转盘选号的功能,直接上代码直接看viewcontroller#... [阅读全文]
  • iOS实现轮盘动态效果

    本文实例为大家分享了ios实现轮盘动态效果的具体代码,供大家参考,具体内容如下一个常用的绘图,主要用来打分之类的动画,效果如下。主要是ios的绘图和动画,本来想... [阅读全文]
  • iOS实现九宫格连线手势解锁

    本文实例为大家分享了ios实现九宫格连线手势解锁的具体代码,供大家参考,具体内容如下demo下载地址:效果图:核心代码://// clockview.m// 手... [阅读全文]
  • iOS实现卡片堆叠效果

    本文实例为大家分享了ios实现卡片堆叠效果的具体代码,供大家参考,具体内容如下如图,这就是最终效果。去年安卓5.0发布的时候,当我看到安卓全新的material... [阅读全文]
  • iOS利用余弦函数实现卡片浏览工具

    iOS利用余弦函数实现卡片浏览工具

    本文实例为大家分享了ios利用余弦函数实现卡片浏览工具的具体代码,供大家参考,具体内容如下一、实现效果通过拖拽屏幕实现卡片移动,左右两侧的卡片随着拖动变小,中间... [阅读全文]
验证码:
移动技术网