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
  • 相关阅读:
    LinqPad 1.31 提供下载
    LINQ to SQL更新数据库操作
    电脑开机进入桌面很慢的解决办法
    VS2008的Linq更新数据就那么费劲
    将图片进行base64编码,并将接受编码后的图片转换为实际图片
    C# 2.0 之 static class
    测试杀毒软件的性能代码
    VS2008 Ajax Toolkit 控件(修正后转载)
    C#发送邮件程序 及测试邮件服务器
    asp.net中的<%%>形式的详细用法实例讲解
  • 原文地址:https://www.cnblogs.com/stevenwuzheng/p/5213908.html
Copyright © 2011-2022 走看看