当tableview/scrollview滚动时定时器NSTimer / CADisplayLink停止响应问题

相信大家在项目中会经常用到NSTimer或CADisplayLink来开启一个定时器,比如在tableView的headerView上添加一个自动滚动的轮播图, 对于NSTimer,可以用 [ NSTimer scheduledTimerWithTimeInterval : 1.0f target : self selector : @selector (timerAction:) userInfo : nil repeats : YES ]; 或   [NSTimer timerWithTimeInterval: 1.0 target: self selector: @selector (timerAction:) userInfo: nil repeats: YES ];  两种方式创建一个定时器。

注:用scheduled的初始化方法将以默认mode(NSDefaultRunLoopMode)直接添加到当前的runloop中;不用scheduled方式初始化的,需要手动addTimer:forMode:timer添加到一个runloop中(一般也会将Mode设置为NSDefaultRunLoopMode)。

对于CADisplayLink,一般会用CADisplayLink *displayLink = [CADisplayLinkdisplayLinkWithTarget:selfselector:@selector(action:)];创建一个定时器,然后

[displayLinkaddToRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];添加到当前的runloop中。这么做的话看起来似乎是没有问题的,但就拿我最近新公司的项目(做直播的)来说吧,项目首页不仅有轮播图,还有几个直播倒计时模块,然后就是项目的直播界面的点赞动画,这几个都是用的NSTimer和CADisplayLink。对于滑动tableView时轮播图不自动滚动这个问题,不能说是一个bug,毕竟这个用户不太会注意,对用户体验影响不大,但首页直播倒计时模块也在tableView滚动时停止工作,这个就有点明显了,更让人接受不了的是当在直播界面滑动聊天消息列表时,旁边点赞动画竟然也停止了。废话说了好多,要解决这个问题需要了解一下runloop的知识(这里只大概说一下),其实就是runloopmode在做怪。runloop可以理解为cocoa下的一种消息循环机制,用来处理各种消息事件,我们在开发的时候并不需要手动去创建一个runloop,因为框架为我们创建了一个默认的runloop,通过[NSRunloop currentRunloop]我们可以得到一个当前线程下面对应的runloop对象,不过我们需要注意的是不同的runloop之间消息的通知方式。在开启一个NSTimer或CADisplayLink实质上是在当前的runloop中注册了一个新的事件源,而当scrollView滚动的时候,当前的MainRunLoop是处于UITrackingRunLoopMode的模式下,在这个模式下,是不会处理NSDefaultRunLoopMode的消息(因为RunLoop Mode不一样),要想在scrollView滚动的同时也接受其它runloop的消息,就不能将Mode参数设置为NSDefaultRunLoopMode,而应该设置为NSRunLoopCommonModes。


你可能感兴趣的:(tableview,scrollview,停止,NSTimer,CADisplayLink)