美文网首页
NSTimer使用注意的问题

NSTimer使用注意的问题

作者: zackwu | 来源:发表于2018-12-27 15:30 被阅读0次

总结一下平时使用NSTimer碰到的几个小问题:

  • 作为定时器使用时不准确的问题
  • ScrollView滚动时timer不执行的问题
  • 内存泄漏的问题

NSTimer准确性不高的原因

以上几个问题都跟RunLoop有关系,一个 NSTimer 注册到RunLoop后,RunLoop 会为其重复的时间点注册好事件。例如 10:00, 10:10, 10:20 这几个时间点。RunLoop为了节省资源,并不会在非常准确的时间点回调这个Timer。Timer 有个属性叫做 Tolerance (宽容度),标示了当时间点到后,容许有多少最大误差。

如果某个时间点被错过了,例如执行了一个很长的任务,则那个时间点的回调也会跳过去,不会延后执行。就比如等公交,如果 10:10 时我忙着玩手机错过了那个点的公交,那我只能等 10:20 这一趟了。

ScrollView滚动时timer不执行的原因

这里有个概念叫 CommonModes:一个 Mode 可以将自己标记为Common属性(通过将其 ModeName 添加到 RunLoopcommonModes 中)。每当 RunLoop 的内容发生变化时,RunLoop 都会自动将 _commonModeItems 里的 Source/Observer/Timer 同步到具有 Common 标记的所有Mode里。

应用场景举例:主线程的 RunLoop 里有两个预置的 Mode:kCFRunLoopDefaultModeUITrackingRunLoopMode。这两个 Mode 都已经被标记为Common属性。DefaultMode 是 App 平时所处的状态,TrackingRunLoopMode 是追踪 ScrollView 滑动时的状态。当你创建一个 Timer 并加到 DefaultMode 时,Timer 会得到重复回调,但此时滑动一个TableView时,RunLoop 会将 mode 切换为 TrackingRunLoopMode,这时 Timer 就不会被回调,并且也不会影响到滑动操作。

有时你需要一个 Timer,在两个 Mode 中都能得到回调,一种办法就是将这个 Timer 分别加入这两个 Mode。还有一种方式,就是将 Timer 加入到顶层的 RunLoop 的 commonModeItems 中。commonModeItems 被 RunLoop 自动更新到所有具有Common属性的 Mode 里去。

NSTimer导致内存泄漏的原因及解决方法

原因
  • NSTimer作为局部变量使用,在添加到RunLoop中的时会被RunLoop强引用,导致Timer本身不能被释放。
  • NSTimer作为属性使用时只能声明成强引用(使用弱引用添加到RunLoop中会导致奔溃),在创建timer的过程中,timer会强引用当前添加的target,若target是当前timer所属的对象时,会造成循环引用的问题
  • timer释放时所在线程跟timer添加到的RunLoop对应的线程不一致时释放会有问题
解决方法

在合适的时机调用invalidate方法。苹果官方的描述如下:

This method is the only way to remove a timer from an NSRunLoop object. The NSRunLoop object removes its strong reference to the timer, either just before the invalidate method returns or at some later point.
If it was configured with target and user info objects, the receiver removes its strong references to those objects as well.

invaliate是唯一一个将timerNSRunLoop对象移除的方法,如果我们是使用targetuserinfo对象创建的,那么同样会移除对这些对象强引用。

#import "TimerViewController.h"

@interface TimerViewController ()

@property (nonatomic, strong) NSTimer *timer;

@end

@implementation TimerViewController

- (void)dealloc {
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self propertyTimer];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    
    if ([self.timer isValid]) {
        [self.timer invalidate];
    }
}

#pragma mark - private method

- (void)propertyTimer {
    self.timer = [NSTimer timerWithTimeInterval:5
                                         target:self
                                       selector:@selector(propertyTimerMethod)
                                       userInfo:nil
                                        repeats:YES];
    
    [[NSRunLoop currentRunLoop] addTimer:self.timer
                                 forMode:NSRunLoopCommonModes];
    [self.timer fire];
}

- (void)propertyTimerMethod {
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

- (void)localTimer {
    //局部变量 无法释放
    NSTimer *timer = [NSTimer timerWithTimeInterval:5
                                             target:self
                                           selector:@selector(localTimerMethod)
                                           userInfo:nil
                                            repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer
                                 forMode:NSRunLoopCommonModes];
    [timer fire];
}

- (void)localTimerMethod {
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

参考

深入理解RunLoop
iOS的几种定时器及区别

相关文章

  • NSTimer循环引用的问题

    问题简介 在iOS中,NSTimer的使用非常频繁,但是NSTimer在使用中需要注意,避免循环引用的问题: 由于...

  • NSTimer使用注意的问题

    总结一下平时使用NSTimer碰到的几个小问题: 作为定时器使用时不准确的问题 ScrollView滚动时time...

  • 内存管理

    一.面试问题 使用CADisplayLink、NSTimer有什么注意点?循环引用、NSTimer定时器不准 介绍...

  • NSTimer循环引用的几种解决方案

    前言 在iOS中,NSTimer的使用是非常频繁的,但是NSTimer在使用中需要注意,避免循环引用的问题。之前经...

  • 内存管理总结

    CADisplayLink、NSTimer使用注意 CADisplayLink、NSTimer会对target产生...

  • CADisplayLink、NSTimer使用注意

    CADisplayLink、NSTimer使用注意 CADisplayLink、NSTimer会对target产生...

  • 底层-内存管理

    CADisplayLink、NSTimer使用注意 CADisplayLink、NSTimer会对target产生...

  • 内存管理

    CADisplayLink、NSTimer使用注意 CADisplayLink、NSTimer会对target产生...

  • iOS内存管理

    CADisplayLink、NSTimer使用注意 CADisplayLink、NSTimer会对target产生...

  • 内存管理

    CADisplayLink、NSTimer使用注意 CADisplayLink、NSTimer会对target产生...

网友评论

      本文标题:NSTimer使用注意的问题

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