定时器

作者: wpf_register | 来源:发表于2016-08-14 08:38 被阅读31次

    参考文档1
    参考文档2

    1.NSTimer

    创建NSTimer

    //常用方法
    + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
    + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
    
    //常用方法
    + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
    + (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
    - (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep
    
    • scheduledTimerWithTimeInterval 方法相比timerWithTimeInterval,不仅初始化了一个timer对象,同时还将该对象放入到当前的Runloop中,而后者需要手动将timer放入runloop。最重要的是NSTimer只有放到runloop才会生效。(runloop后面会专门写一下)。
    -(void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
    
    • timer定时器并不是一个精确运行的,精确运行需要用GCDtimer
    • 正常情况下tableView等滚动视图添加timer后,视图滚动后
      RunLoop会将mode切换成TrackingRunLoopMode 不会调用timer
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateUI) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    //NSRunLoopCommonModes的意思为,定时器可以运行在标记为common modes模式下。
    //具体包括两种: kCFRunloopDefaultMode  和   UITrackingRunloopMode。
    [timer fire];
    

    暂停/启动NSTimer

    //启动,常用方法创建的直接就启动了
    [self.timer setFireDate:[NSDate distantPast]];
    //暂停
    [self.timer setFireDate:[NSDate distantFuture]];
    

    释放NSTimer

    释放写在viewWillDisappear!!!!!
    [self.timer invalidate];//将timer停止并移出runloop
    self.timer = nil;
    
    NSTimer在ARC下
    • 初始化后放到runloop后,除了ViewController外,iOS系统也强引用NSTimer对象。

    • 将timer对象置nil后,会解除VC对timer的中引用。但iOS系统依然对NSTimer和VC存在强引用关系。(因为并未解除系统对timer的强引用,并且系统为了实现NSTimer而对VC继续保持引用)。所以先对timer 执行invalidate(解系统对timer的强引用),再置nil(解除VC对timer引用)。

    • 由于系统和VC对timer的双重引用,导致dealloc 方法无法执行,所以理想的方法是释放代码写在viewWillDisappear方法中。

    2.GCD

    dispatch source是一个监视某些类型事件的对象。
    当这些事件发生时,它自动将一个block放入一个dispatch queue的执行例程中。
        /**
         *  创建dispatch源
         *
         *  @param DISPATCH_SOURCE_TYPE_TIMER 事件源的类型
         *  @param 0                          <#0 description#>
         *  @param 0                          <#0 description#>
         *  @param dispatch_get_main_queue    在哪个线程上执行
         *
         *  @return dispatch_source_t
         */
        dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
        /**
         * @param start 控制计时器第一次触发的时刻
         * @param interval 每隔多长时间执行一次
         * @param leeway 误差值,0表示最小误差,值越小性能消耗越大
         */
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    
        //事件处理的回调
        dispatch_source_set_event_handler(timer, ^{
            
        });
    
        // Dispatch source启动时默认状态是挂起的,创建完毕之后得主动恢复,
        //否则事件不会被传递,也不会被执行
        dispatch_resume(timer);
        //取消定时器
        dispatch_cancel(timer);
    

    3.CADisplayLink

    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(disPlay)];
    //与NSTimer不同, 需要手动添加到RunLoop中, 如果添加的模式是NSDefaultRunLoopMode, 则scrollview滚动时, 会阻碍定时器的执行。
    //如果是NSRunLoopCommonModes, 则不会阻碍。
        [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    //设置刷新频率, 默认是每秒60帧, 如果设置成60就每秒执行一次
    //但是实际测试却发现,设置60是2秒执行一次, 设置成30才是每秒执行一次。但精度依然比NSTimer高
        displayLink.frameInterval = 60;
    

    相关文章

      网友评论

          本文标题:定时器

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