iOS开发之UITableView中计时器的几种实现方式(NSTimer、DispatchSource、CADisplayLink)
最近工作比较忙,但是还是出来更新博客了。今天博客中所涉及的内容并不复杂,都是一些平时常见的一些问题,通过这篇博客算是对UITableView中使用定时器的几种方式进行总结。本篇博客会给出在TableView中使用NSTimer或者DispatchSourcer中常见的五种方式。当然下方第一种方式是常规做法,不过也是UITableView中使用NSTimer的一个坑。其他三种方式是为了绕过这个坑的解决方案。
当然,本篇博客共涉及到了UITableView中使用定时器的四种实现方式,当然应该也还有其他实现方式,只不过目前我没有涉及到。欢迎在评论区提供其他实现方式,我会及时的整合到目前的Demo中。
接下来我们先来总结一下本篇博客所涉及的四种方式:
第一种就是直接在TableView的Cell上使用NSTimer,当然这种方式是有问题的,稍后会介绍。
第二种是将NSTimer添加到当前线程所对应的RunLoop中的commonModes中。
第三种是通过Dispatch中的TimerSource来实现定时器。
第四种是开启一个新的子线程,将NSTimer添加到这个子线程中的RunLoop中,并使用DefaultRunLoopModes来执行。
第五种方式就是使用CADisplayLink来实现。
下方我们将会根据具体的示例来详细的介绍以上这五种实现方式。
一、在Cell中直接使用NSTimer
首先我们按照常规做法,直接在UITableView的Cell上添加相应的NSTimer, 并使用scheduledTimer执行相应的代码块。这种方式没有什么特殊的就是对Timer的直接使用。下方是我们本部分的Timer的使用代码,当然是使用Swift来实现的,不过与OC的代码差不多。代码如下所示 :

上述代码比较简单,就是在Cell上添加了一个定时器,然后没1秒更新一次时间,并在Cell的timeLabel上显示,运行效果如下所示。从该运行效果中我们不难发现,当我们滑动TableView时,该定时器就停止了工作。具体原因就是当前线程的RunLoop在TableView滑动时将DefaultMode切换到了TrackingRunLoopMode。因为Timer默认是添加在RunLoop上的DefaultMode上的,当Mode切换后Timer就停止了运行。
但是当停止滑动后,Mode又切换了回来,所以Timer有可以正常工作了。

为了进一步看一下Mode的切换,我们可以在相应的地方获取当前线程的RunLoop并且打印对应的Mode。下方代码就是在TableView所对应的VC上添加的,我们在viewDidLoad()、viewDidAppear()以及scrollViewDidScroll()这个代理方法中对当前线程所对应的RunLoop下的currentMode进行了打印,其代码如下。


下方就是最终的运行结果。从输出结果中我们不难看出,在viewDidLoad()方法中打印的Current Mode为UIInitializationRunLoopMode, 从该Mode的名字中我们不难发现,该Mode负责UI的初始化。在viewDidApperar()方法中,也就是UI显示后,RunLoop的Mode切换成了kCFRunLoopDefaultMode。紧接着,我们去滑动TableView,然后在scrollViewDidScroll()代理方法中打印滑动时当前RunLoop所对应的Mode。从下方运行结果不难看出,当TableView滑动时,打印出的currentModel为UITrackingRunLoopMode。当停止滑动后,点击Show Current Mode按钮获取当前Mode时,打印的有时RunLoopDefaultMode。具体如下所示:

二、将Timer添加到CommonMode中
上一部分的定时器是不能正常运行的,因为NSTimer对象默认添加到了当前RunLoop的DefaultMode中,而在切换成TrackingRunLoopMode时,定时器就停止了工作。解决该问题最直接方法是,将NSTimer在TrackingRunLoopMode中也添加一份。这样的话无论是在DefaultMode还是TrackingRunLoopMode中,定时器都会正常的工作。
如果你对RunLoop比较熟悉的话,可以知道CommonModes就是DefaultMode和TrackingRunLoopMode的集合,所以我们只需要将NSTimer对象与当前线程所对应的RunLoop中的CommonModes关联即可,具体代码如下所示:

上述代码与第一部分的代码不同的地方在于我们将创建好的定时器添加到了当前RunLoop中的CommonModes中,这样的话可以保证TableView在滑动时定时器也可以正常运行。上述代码最终的运行效果如下所示。

从该运行效果我们不难发现,当该TableView滚动式,其Cell上的定时器是可以正常工作的。但是当我们滑动右上角的这个TableView时,第一个的TableView中的定时器也是不能正常工作的,因为这些TableView都在主线程中工作,也就是说这些TableView所在的RunLoop是同一个。
三、将Timer添加到子线程的RunLoop下的DefaultMode中
接下来我们来看另一种解决方案,就是开启一个新的子线程,然后将Timer添加到这个子线程所对应的RunLoop中。当然因为是子线程的RunLoop,在添加Timer时,我们可以将Timer添加到子线程中的RunLoop中的DefaultMode中。添加完毕后,手动运行该RunLoop。
因为是在子线程中添加的Timer, Timer肯定是在子线程中工作的,所以在更新UI时,我们需要在主线程中进行更新,具体代码如下所示:

在上述代码中我们可以看到我们使用全局的并行队列来异步创建了一个Timer对象,然后将该对象添加进了该异步线程中的DefaultRunLoopMode中,然后运行该RunLoop。当然在子线程中更新UI还是需要在主线程中去操作的。下方就是上述代码的运行效果。从该效果中我们不难看出,当滑动TableView时定时器是可以正常工作的。

四、DispatchTimerSource
接下来我们就不使用NSTimer来实现定时器了。在之前的博客中聊GCD时其中用到了DispatchTimerSource来实现定时器。接下来我们就在TableView的Cell上添加DispatchTimerSource,然后看一下运行效果。当然下方代码片段我们是在全局队列中添加的DispatchTimerSource,在主线程中进行更新。当然我们也可以在mainQueue中添加DispatchTimerSource,这样也是可以正常工作的。当然我们不建议在MainQueue中做,因为在编程时尽量的把一些和主线程关联不太大的操作放到子线程中去做。代码如下所示:

接下来我们来看一下上述的代码的运行效果,从该效果中我们可以看出该定时器是可以正常工作的。

五、CADisplayLink
接下来我们来使用CADisplayLink来实现定时器功能,在之前的博客中我们也使用过CADisplayLink,不过是用来计算FPS的。下方代码片段中我们就使用CADisplayLink来实现的定时器。CADisplayLink可以添加到RunLoop中,RunLoop的每一次循环都会触发CADisplayLink所关联的方法。在屏幕不卡顿的情况下,每次循环的时间时1/60秒。
下方代码,为了不让屏幕的卡顿等引起的主线程所对应的RunLoop阻塞所造成的定时器不精确的问题。我们开启了一个新的线程,并且将CADisplayLink对象添加到这个子线程的RunLoop中,然后在主线程中更新UI即可。具体代码如下:

我们对上述代码运行,下方是其对应的运行结果。从下方运行结果中我们不难看出,在TableView滚动时该定时器也是可以正常运行的。当然该方式实现的定时器的精度是比较高的。

经过上述五大部分,我们罗列了定时器的几种实现方式,通过对比我们不难发现其优劣性。上述定时器中DispatchSourceTime以及CADisplayLink的精度要比NSTimer的精度要高。从代码实现中我们不难看出CADisplayLink的精度是比较高的。
本篇博客所涉及代码的github分享地址为:https://github.com/lizelu/NSTimerWithRunLoop
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #00b1ff }
span.s1 { }
iOS开发之UITableView中计时器的几种实现方式(NSTimer、DispatchSource、CADisplayLink)的更多相关文章
- iOS开发之UITableView的使用
这一篇记录的是iOS开发中UITableView的使用,iOS中的UITableView跟Android中的ListView特别相似,以下用一个Demo来说明: 1.Xcode中新建projectTe ...
- iOS开发之UITableView使用总结
什么是UITableView 在众多移动应用中,能看到各式各样的表格数据 在iOS中,要实现表格数据展示,最常用的做法就是使用UITableView UITableView继承自UIScrollVie ...
- iOS开发之UITableView及cell重用
1.UITanleview有的两种风格 一种是Plain,一种是Grouped,可以从这里设置风格: 他们样式分别如下: Plain: Grouped: 2.tableView展示数据的过程: (1) ...
- ios开发之xcode6中如何添加pch全局引用文件
xcode6中去掉了默认添加pch文件,这就需要我们自己手动添加pch文件了,添加pch文件是为了一些琐碎的头文件引用,加快编译速度! 下面就说下该如何手动添加pch文件: 1.添加一个文件,在oth ...
- iOS开发之AutoLayout中的Content Hugging Priority和 Content Compression Resistance Priority解析
本篇博客的内容也不算太复杂,算是AutoLayout的一些高级的用法.本篇博客我们主要通过一些示例来看一下AutoLayout中的Content Hugging Priority以及Content C ...
- Android 开发之旅:view的几种布局方式及实践
本文的主要内容就是分别介绍以上视图的七种布局显示方式效果及实现,大纲如下: 1.View布局概述 2.线性布局(Linear Layout) 2.1.Tips:android:layout_weigh ...
- iOS开发之MVVM在项目中的应用
今天写这篇博客是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇博客的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...
- 李洪强iOS开发之RunLoop的原理和核心机制
李洪强iOS开发之RunLoop的原理和核心机制 搞iOS之后一直没有深入研究过RunLoop,非常的惭愧.刚好前一阵子负责性能优化项目,需要利用RunLoop做性能优化和性能检测,趁着这个机会深入研 ...
- iOS开发之Socket通信实战--Request请求数据包编码模块
实际上在iOS很多应用开发中,大部分用的网络通信都是http/https协议,除非有特殊的需求会用到Socket网络协议进行网络数 据传输,这时候在iOS客户端就需要很好的第三方CocoaAsyncS ...
随机推荐
- 【Eclipse】代码格式化 快捷键无效
原因:搜狗输入法 简繁切换与eclipse代码格式化冲突 解决:在搜狗输入法-->按键-->修改即可.
- 汉化Eclipse
汉化Eclipse.. ----------------- /--------------------------------link连接: 将下载的语言包解压后会有eclipse文件夹,eclips ...
- LNMP1.4环境中安装fileinfo插件
安装前: 安装前建议先执行 /usr/local/php/bin/php -m (此命令显示目前已经安装好的PHP模块)看一下,要安装的模块是否已安装. 然后下载当前PHP版本的源码并解压. 安装: ...
- 论述Redis和Memcached的差异
原文 https://yq.aliyun.com/articles/60981?utm_campaign=wenzhang&utm_medium=article&utm_source= ...
- java语言基础(变量和运算符)
java八大基本数据类型: 整型{ int(整型) short(短整型) long(长整型)} 浮点型{ float(浮点型) double(双精度)} 布尔{boolean} ...
- java内存管理(堆、栈、方法区)
java内存管理 简介 首先我们要了解我们为什么要学习java虚拟机的内存管理,不是java的gc垃圾回收机制都帮我们释放了内存了吗?但是在写程序的过程中却也往往因为不懂内存管理而造成了一些不容易察觉 ...
- CAS单点登陆 SSO
什么是单点登陆 SO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制.它是目前比较流行的企业业务整合的解决方 ...
- Error:Failed to load project configuration:xxxxxxxxxxxxxxxxxxxx cannot read file .idea/misc.xml
你这idea不会没有配置默认jdk吧?你看看File--other settings--default project structure,看看project setting的project里面,有没 ...
- 【Java线程】Java内存模型总结
学习资料:http://www.infoq.com/cn/articles/Java-memory-model-1 Java的并发采用的是共享内存模型(而非消息传递模型),线程之间共享程序的公共状态, ...
- JAVA课程设计
博客作业教学数据分析系统(From:网络五条狗) 通过网络爬虫技术,将每位同学的分数链接爬到数据库,并根据每位同学该次作业的分数链接,获取该次作业的浏览量.评论量.图片数等信息,接着根据Java班级博 ...