iOS中的定时器

iOS中的定时器,第1张

创建方式:

需要添通过 addTimer:forMode: 加到当前线程的runloop

如果只是执行延时 *** 作,可以用:

以上的所有方法创建的定时器,如果在子线程中运行是需要开启runloop的

影响NSTimer的原因:

计时器对象,与屏幕的刷新率同步。

iOS 设备的屏幕刷新频率是固定的,其精度相当准确,一般用于做 UI 界面的不停重绘

GCD中的 dispatch_source 常见的场景就是定时器功能, dispatch_source_t 系统级的源事件,由系统自动触发,高精度

void dispatch_source_set_timer(dispatch_source_t source,dispatch_time_t start,uint64_t interval,uint64_t leeway)

参数1:source 创建的定时器timer

参数2:DISPATCH_TIME_NOW

DISPATCH_SOURCE_TYPE_TIMER系统会使用默认时钟来进行计时,当系统休眠的时候,默认时钟是不走的,也就会导致计时器停止。

dispatch_walltime(NULL,0)可以让计时器按照真实时间间隔进行计时。

参数3:间隔时间

参数4:容错,如果设置为1秒,系统可能会在任务时间到达前1秒或后1秒执行

创建好的定时器,需要手动开启:

等到指定的时间通过异步的方式将提其提交到指定的队列中执行

dispatch_time 第一个参数:dispatch_time_t

DISPATCH_TIME_NOW: 0

DISPATCH_TIME_FOREVER: 无穷大

这里0.36代表 0.36秒之后执行任务

在iOS中我们常用的定时器有三种: Timer, CADisplayLink, DispatchSourceTimer

Timer是我们最常见的定时器,当定时器创建完(不用 scheduled 的,需要手动添加到 runloop 中)后,该定时器将在初始化时指定的 t 秒后自动触发。我们经常围绕它的俩个问题是 精度 循环引用 问题。

如果Timer是加在main runloop中,就很容易因为主线程忙于各种UI *** 作或者复杂的运算导致阻塞线程,从而使得NSTimer延迟执行,导致精度较低。

Timer如果想要更高点的精度,我们可以从以下几个方面考虑

我们知道Timer的调用有target-action和block俩种方式,其中target-action会导致循环引用,造成内存泄露的问题, 因为target, action,runLoop之间有强引用链导致,解决办法

1.使用block回调方式

2.使用NSProxy类作为中间对象

CADisplayLink通过和屏幕刷新相同的频率将内容显示到屏幕上。也是依赖于NSRunLoop运行,iOS设备的屏幕刷新频率是固定的,CADisplayLink在通常都会在在每次刷新结束调用,精度较高,更适合做屏幕刷新等

DispatchSourceTimer精度很高,因为是系统级别,且是不受RunLoop影响。

常见基础用法

计时器对象,与屏幕的刷新率同步。

iOS设备的屏幕刷新频率是固定的,其精度相当准确,一般用于做UI界面的不停重绘。

NSTimer比较常用的创建方法有以下两种:

scheduledTimerWithTimeInterval 在主线程创建的定时器会在创建后自动将timer添加到主线程的RunLoop中并启动,主线程的RunLoopMode为 NSDefaultRunLoopMode ,如果有滚动视图并滑动的时候,执行的是 UITrackingRunLoopMode , NSDefaultRunLoopMode 被挂起,定时器失效,等到滑动结束才恢复。

因此需要将timer分别加入 UITrackingRunLoopMode 和 NSDefaultRunLoopMode 中:

或者直接添加到 NSRunLoopCommonModes 中:

也可以新开一个子线程,主线程的RunLoop默认是开启的,子线程的RunLoop需要手动开启:

创建个继承自NSObject的类

使用

也可以使用NSProxy来解决循环引用。

创建一个继承自NSProxy的类,

创建一个 NSTimer (Weak)

使用时需注意,先定义了一个弱引用,令其指向self,然后使块捕获这个引用,而不直接去捕获普通的self变量。也就是说,self不会为计时器所保留。当块开始执行时,立刻生成strong引用,以保证实例在执行期间持续存活。

情况产生:

1、NSTimer被添加在mainRunLoop中,模式是NSDefaultRunLoopMode,mainRunLoop负责所有主线程事件,例如UI界面的 *** 作,复杂的运算使当前RunLoop持续的时间超过了定时器的间隔时间,那么下一次定时就被延后,这样就会造成timer的阻塞、2:模式的切换,当创建的timer被加入到NSDefaultRunLoopMode时,此时如果有滑动UIScrollView的 *** 作,runLoop 的mode会切换为TrackingRunLoopMode,这时timer会停止回调。

GCD 定时器比 NSTimer 更精确,定时器一定要被强引用,不然会被释放,导致的定时器无效。

创建一个GCD定时器LWTTimer

使用:


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/6767101.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-28
下一篇 2023-03-28

发表评论

登录后才能评论

评论列表(0条)

保存