美文网首页iOS bug修复程序员iOS进阶指南
Tips:NSTimer需要注意的两个小问题

Tips:NSTimer需要注意的两个小问题

作者: KevinTing | 来源:发表于2016-04-20 22:21 被阅读404次

    1、scrollView滚动时NSTimer暂停的问题

    便利构造方法 + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;会将timer直接绑定到NSDefaultRunLoopMode,而在scrollView滚动的时候处于UITrackingRunLoopMode下,是不会处理NSRunLoopDefaultMode的消息的,因此此时应该手动添加timer到NSRunLoopCommonModes下面。

    timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(doSomething) userInfo:nil repeats:NO];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    

    2、UIView的NSTimer内存释放

    如果你的View有一个property:

    @property(nonatomic, strong) NSTimer *timer;
    

    然后你初始化并执行一个循环动画

    - (void)start
    {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(handleTimer:) userInfo:nil repeats:YES];
    }
    
    -(void)handleTimer:(NSTimer *)theTimer
    {
        // 动画
    }
    

    你应该知道NSTimer需要invalidate才能使得view能够dealloc。但是这样写是自欺欺人的做法:

    - (void)stopTimer
    {
        [self.timer invalidate];
        self.timer = nil;
    }
    
    - (void)dealloc
    {
        [self stopTimer];
    }
    

    你陷入了鸡生蛋,蛋生鸡的悖论中。。。你要view死,然后才invalidate,但是view非要等到你invalidate才能死啊!如果你又不想在外面显示的调用stopTimer,那么这样做比较合适,在view移除出视图结构的时候

    - (void)willMoveToSuperview:(UIView *)newSuperview
    {
        if (!newSuperview)
        {
            [self stopTimer];
        }
    }
    

    另外也可以参照《Effective Objective-C 2.0》书中的做法:采用block的方式,推荐用这种,ios 10中已经提供了这个API了。

    @interface NSTimer (OVExtension)
    
    // 避免 timer 循环引用,自动释放
    // ios 10 已经有了这个 api,但是 ios8 和 ios9 不支持
    + (instancetype)ov_scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)())block;
    
    @end
    
    @implementation NSTimer (OVExtension)
    
    + (instancetype)ov_scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)())block
    {
        return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(ov_blockInvoke:) userInfo:[block copy] repeats:repeats];
    }
    
    + (void)ov_blockInvoke:(NSTimer *)timer
    {
        void (^block)() = timer.userInfo;
        if (block) {
            block();
        }
    }
    
    @end
    
    

    相关文章

      网友评论

      • a05832db24ea:我觉得肠粉好腻说说它的精度问题,我在Mac下用,发现最大精度一般是15毫秒左右

      本文标题:Tips:NSTimer需要注意的两个小问题

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