zoukankan      html  css  js  c++  java
  • iOS定时器-- NSTimer 和CADisplaylink

    iOS定时器-- NSTimer 和CADisplaylink

     

    一、iOS中有两种不同的定时器:

    1.  NSTimer(时间间隔可以任意设定,最小0.1ms)// If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead.

    2.  CADisplayLink(时间间隔不能设置,与显示器刷新频率一直)

     

    二、创建和启动定时器的3种方式:

    // 方式1

    [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(nextImage) userInfo:nil repeats:YES]; //会自动加入当前的runloop消息循环中,不用手写[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

    // 方式2

    // 创建 NSTimer 对象

    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(test1) userInfo:nil repeats:YES];

    //将刚创建的 NSTimer 对象加到消息循环中, 这样就会自动启动定时器

    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];

    [runLoop addTimer:timer forMode:NSRunLoopCommonModes];

    // 方式3

    // 创建计时器对象

    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(test1) userInfo:nil repeats:YES]

    // 每次调用一次 fire 执行一次 test1方法

    [timer fire]; // 执行一次 test 方法

    [timer fire]; // 执行一次 test 方法

    [timer fire]; // 执行一次 test 方法

    [timer fire]; // 执行一次 test 方法

    三、关于NSRunLoop相关知识:

    先看看NSTimer的两个常用方法:

    + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo; //生成timer但不执行

    + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo; //生成timer并且纳入当前线程的run loop来执行

     

    NSRunLoop与timer有关方法为:

    - (void)addTimer:(NSTimer *)timer forMode:(NSString *)mode; //在run loop上注册timer

     

    理解run loop后,才能彻底理解NSTimer的实现原理,也就是说NSTimer实际上依赖run loop实现的。

    主线程已经有run loop,所以NSTimer一般在主线程上运行都不必再调用addTimer: 。

    但在非主线程上运行必须配置run loop,NSTimer在非主线程的main方法中使用,示例代码如下:

    - (void)main

    {

      NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timer:) userInfo:nil repeats:YES];

      NSRunLoop *runLoop = [NSRunLoop currentRunLoop];

      [runLoop addTimer:myTimer forMode:NSDefaultRunLoopMode]; //实际上这步是不需要,scheduledTimerWithTimeInterval已经纳入当前线程运行。如果使用timerWithTimeInterval则需要

      while (xxx条件)

        [runLoop run];

    }

    实际上这个线程无法退出,因为有timer事件需要处理,[runLoop run]会一直无法返回。解决办法就是设置一个截止时间:

    [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]]; //每隔10秒检查下线程循环条件,当然时间值可以根据实际情况来定。

     

    特别注意:

    我们通常在主线程中使用NSTimer,有个实际遇到的问题需要注意。当滑动界面时,系统为了更好地处理UI事件和滚动显示,主线程runloop会暂时停止处理一些其它事件,这时主线程中运行的NSTimer就会被暂停。解决办法就是改变NSTimer运行的mode(mode可以看成事件类型),不使用缺省的NSDefaultRunLoopMode,而是改用NSRunLoopCommonModes,这样主线程就会继续处理NSTimer事件了。具体代码如下:

    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timer:) userInfo:nil repeats:YES];

    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

     

    ios开发经常用到的延迟调用的方法,其实就是在当前线程的run loop上注册timer来实现定时运行的。所以如果是在非主线程上使用,一定要有一个run loop。

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

    - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;

     

    四、关于CADisplaylink相关知识

    注意:
    严格意义上讲 CADisplayLink 并不是计时器控件, 它是与显示器刷新频率一致的。比如显示的刷新频率是60赫兹, 那么 CADisplayLink 就会每秒钟执行60次。正是因为这个原因所以有时也把 CADisplayLink 当做计时器控件来使用。CADisplayLink:每次屏幕刷新的时候就会调用,屏幕一般一秒刷新60次。

    //CADisplayLink应用举例

    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(timerAction)];

    [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];  // 添加主运行循环

    - (void)timerAction

    { // 注意:这个方法并不会马上调用drawRect,其实这个方法只是给当前控件添加刷新的标记,等下一次屏幕刷新的时候才会调用drawRect

        [self setNeedsDisplay];

    }

    //如果想把一些文字/图片等绘制在自定义的WZView上,必须在drawRect里写代码

    - (void)drawRect:(CGRect)rect {

        // 如果以后想绘制东西到view上面,必须在drawRect方法里面,不管有没有手动获取到上下文

        UIImage *image =  [UIImage imageNamed:@"雪花"];

        [image drawAtPoint:CGPointMake(50, _snowY)];

    }

     

    五、NSTimer 和CADisplaylink的区别:

    1. 如果在绘图的时候需要用到定时器,通常CADisplaylink, NSTimer很少用于绘图,因为调度优先级比较低,并不会准时调用。

    2. 使用绘图产生动画时,一般用CADisplaylink定时器在@selector(timerAction:)方法里调用[self setNeedsDisplay];方法,因为CADisplaylink是在屏幕刷新时调用一次timerAction:方法,而setNeedsDisplay方法也是在屏幕刷新时调用drawRect方法重绘图形,二者刚好同步。这样产生的动画就非常流畅,不会有卡顿的感觉。

     

     

    文章系作者原创,转载请注明出处:http://www.cnblogs.com/stevenwuzheng/p/5213908.html

    如有错误,欢迎随时指正!

     

     

    iOS开发者交流群:180080550
  • 相关阅读:
    Java实现 计蒜客 拯救行动
    Java实现 计蒜客 拯救行动
    Java实现 LeetCode 174 地下城游戏
    Java实现 LeetCode 174 地下城游戏
    Java实现 LeetCode 174 地下城游戏
    Java实现 LeetCode 173 二叉搜索树迭代器
    Java实现 LeetCode 173 二叉搜索树迭代器
    Visual Studio的SDK配置
    怎样使用CMenu类
    mfc menu用法一
  • 原文地址:https://www.cnblogs.com/stevenwuzheng/p/5213908.html
Copyright © 2011-2022 走看看