iOS DispatchSourceTimer 定时器的具体使用

目录
  • 1. 概述
  • 2. DispatchSourceTimer
    • 2.1 GCD Timer 创建
    • 2.2 GCD Timer 配置
    • 2.3 GCD Timer 部署任务
    • 2.4 GCD Timer控制方法
    • 2.5 双重循环 DispatchSourceTimer
  • 参考文章

1. 概述

说起计时器,很多开发人员第一时间就会想起Timer,但是随着使用的深入,慢慢就发现Timer其实不是很好用,比如说TableView滑动时候不执行,Timer循环应用。

2. DispatchSourceTimer

DispatchSourceTimer,也就是大家通常叫的GCD Timer,是依赖于GCD的一种Timer,Runloop的底层代码中也用到这种Timer,可见GCD Timer并不依赖与Runloop。

先看一下苹果的定义:

A dispatch source that submits the event handler block based on a timer.

2.1 GCD Timer 创建

使用下面的方法即可创建一个DispatchSourceTimer对象。

class func makeTimerSource(flags: DispatchSource.TimerFlags = [], queue: DispatchQueue? = nil) -> DispatchSourceTimer
// 默认在主队列中调度使用
let timer = DispatchSource.makeTimerSource()
// 指定在主队列中调度使用
let timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
// 指定在全局队列中调度使用
let timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.global())
// 指定在自定义队列中调度使用
let customQueue = DispatchQueue(label: "customQueue")
let timer = DispatchSource.makeTimerSource(flags: [], queue: customQueue)

2.2 GCD Timer 配置

配置Timer参数,需要使用DispatchSourceTimer协议的方法。可以安排一次或多次触发的Timer。Timer每次触发的时候,都会调用已部署的任务。

    // 从现在开始,每秒执行一次。
    timer?.schedule(deadline: DispatchTime.now(), repeating: .seconds(1), leeway: .nanoseconds(1))
    // 5秒之后执行任务,不重复。
    timer?.schedule(deadline: DispatchTime.now() + 5, repeating: .never, leeway: .nanoseconds(1))

2.3 GCD Timer 部署任务

当Timer配置完参数后,使用DispatchSourceProtocol协议的方法来部署要执行的任务。

setEventHandler和setRegistrationHandler的区别:

  • setEventHandler:给Timer设置要执行的任务,包括一次性任务和定时重复的任务。回调方法在子线程中执行。
  • setRegistrationHandler:这个方法设置的任务只会执行一次,也就是在Timer就绪后开始运行的时候执行,类似于Timer开始的一个通知回调。回调方法在子线程中执行。

例如下面的代码:

var timer: DispatchSourceTimer?

func initTimer() {
    // 默认在主队列中调度使用
    timer = DispatchSource.makeTimerSource()

    // 从现在开始,每秒执行一次。
    timer?.schedule(deadline: DispatchTime.now(), repeating: .seconds(1), leeway: .nanoseconds(1))
    // 5秒之后执行任务,不重复。

// timer?.schedule(deadline: DispatchTime.now() + 5, repeating: .never, leeway: .nanoseconds(1))

    timer?.setEventHandler {
        DispatchQueue.main.async {
            print("执行任务")
        }
    }

    timer?.setRegistrationHandler(handler: {
        DispatchQueue.main.async {
            print("Timer开始工作了")
        }
    })
    timer?.activate()
}

执行结果如下:

2020-11-28 02:20:00 +0000 Timer开始工作了
2020-11-28 02:20:00 +0000 执行任务
2020-11-28 02:20:01 +0000 执行任务
2020-11-28 02:20:02 +0000 执行任务

2.4 GCD Timer控制方法

下面看一下Timer的一下控制方法及状态:

  • activate() : 当创建完一个Timer之后,其处于未激活的状态,所以要执行Timer,需要调用该方法。
  • suspend() : 当Timer开始运行后,调用该方法便会将Timer挂起,即暂停。
  • resume() : 当Timer被挂起后,调用该方法便会将Timer继续运行。
  • cancel() : 调用该方法后,Timer将会被取消,被取消的Timer如果想再执行任务,则需要重新创建。

上面的这些方法如果使用不当,很容易造成APP崩溃,下面来看一下具体注意事项及建议:

  • 当Timer创建完后,建议调用activate()方法开始运行。如果直接调用resume()也可以开始运行。
  • suspend()的时候,并不会停止当前正在执行的event事件,而是会停止下一次event事件。
  • 当Timer处于suspend的状态时,如果销毁Timer或其所属的控制器,会导致APP奔溃。
  • 2020-11-28 02:20:00 +0000 Timer开始工作了
    2020-11-28 02:20:00 +0000 执行任务
    2020-11-28 02:20:01 +0000 执行任务
    2020-11-28 02:20:02 +0000 执行任务
    suspend()和resume()需要成对出现,挂起一次,恢复一次,如果Timer开始运行后,在没有suspend的时候,直接调用resume(),会导致APP崩溃。
  • 使用cancel()的时候,如果Timer处于suspend状态,APP崩溃。
  • 另外需要注意block的循环引用问题。

2.5 双重循环 DispatchSourceTimer

比如:我们需要一定时间情况下(数组长度*4),每隔一段时间打印对应下标(每个元素隔4秒打印),无限打印

在下面例子的双重循环中使用 DispatchSourceTimer 你会发现print只打印了 dom some = 0 这个不是我们想要的效果

var exaltedTimer: DispatchSourceTimer?

func demo {
    let arr = [1,2,3,4]

    self.exaltedTimer = DispatchSource.makeTimerSource()
    self.exaltedTimer?.schedule(deadline: .now(), repeating: TimeInterval(arr.count*4))

    self.exaltedTimer?.setEventHandler(handler: {

        for (index, item) in arr.enumerated() {

            let timer2 = DispatchSource.makeTimerSource()
            timer2.schedule(deadline: .now()+4.0*CGFloat(index), repeating: .infinity)
            timer2.setEventHandler {
                DispatchQueue.main.async {
                    print("do some = \(index)")
                }
            }

            timer2.activate()

        }
    })
    self.exaltedTimer?.activate()
}

这个是因为timer2使用之后就被释放了,所以要cancel和resume配合使用,这样就实现了我们想要的效果了。

var exaltedTimer: DispatchSourceTimer?

var exaltedTimerArray: [DispatchSourceTimer] = []

func demo {

    self.exaltedTimer?.cancel()
    for subTimer in self.exaltedTimerArray {
        subTimer.cancel()
    }

    let arr = [1,2,3,4]

    self.exaltedTimer = DispatchSource.makeTimerSource()
    self.exaltedTimer?.schedule(deadline: .now(), repeating: TimeInterval(arr.count*4))

    self.exaltedTimer?.setEventHandler(handler: {

        for (index, item) in arr.enumerated() {

            let timer2 = DispatchSource.makeTimerSource()
            timer2.schedule(deadline: .now()+4.0*CGFloat(index), repeating: .infinity)
            timer2.setEventHandler {
                DispatchQueue.main.async {
                    print("do some = \(index)")
                }
            }

            self.exaltedTimerArray.append(timer2)
            timer2.resume()

        }
    })
    self.exaltedTimer?.resume()

参考文章

https://blog.csdn.net/guoyongming925/article/details/110224064

到此这篇关于iOS DispatchSourceTimer 定时器的具体使用的文章就介绍到这了,更多相关iOS DispatchSourceTimer 定时器内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2022-05-06

iOS中几种定时器的实现小结

在软件开发过程中,我们常常需要在某个时间后执行某个方法,或者是按照某个周期一直执行某个方法.在这个时候,我们就需要用到定时器. 然而,在iOS中有很多方法完成以上的任务,到底有多少种方法呢?经过查阅资料,大概有三种方法:NSTimer.CADisplayLink.GCD.接下来我就一一介绍它们的用法. 一.NSTimer 1. 创建方法 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selecto

iOS中最全的各种定时器使用教程

前言 相信一说到定时器, 我们使用最多的就是NSTimer 和 GCD 了, 还有另外一个高级的定时器 CADisplayLink;,下面将给大家详细介绍关于iOS定时器使用的相关内容,话不多说了,来一起看看详细的介绍吧. 一. NSTimer NSTimer的初始化方法有以下几种: 会自动启动, 并加入 MainRunloop 的 NSDefaultRunLoopMode 中, 注意: 这里的自动启动, 并不是马上就会启动, 而是会延迟大概一个interval的时间: + (NSTimer *

iOS仿小红书呼吸灯动画(核心动画和定时器)两种方式实现

最近公司需求做个类似小红书的标签呼吸灯动画,经过一段时间研究使用两种方式实现了该效果... 第一种方式使用定时器加 UIView动画,核心方法如下 -(void)begigFlashAnimation { // 缩放 + 透明度动画 self.flashView.transform = CGAffineTransformMakeScale(0.1, 0.1); [UIView animateWithDuration:3 animations:^{ self.flashView.transform

iOS开发定时器的三种方法分享

前言 在开发中,很多时候我们需要用到定时器实时刷新某个数值.这个时候我们就需要用到定时器,这里,我为大家推荐三种方法,分别是:NSTimer.CADisplayLink.GCD.接下来我就一一介绍它们的用法.希望能帮到大家. 一.NSTimer(一般用于定时的更新一些非界面上的数据) 1. 创建方法 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(action:

iOS中的NSTimer定时器的初步使用解析

创建一个定时器(NSTimer) - (void)viewDidLoad { [super viewDidLoad]; [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(actionTimer:) userInfo:nil repeats:YES]; } - (void)actionTimer:(NSTimer *)timer { } NSTimer默认运行在default mode下,default

IOS 中NSTimer定时器的使用

IOS 中NSTimer定时器的使用 NSTimery 定时器,主要用于进行定时执行指定方法,常用场景如:获取验证码的按钮倒计时:图片轮播定时. 1 使用注意事项: 1.1 倒计时时间间隔(时间单位是秒) 1.2 指定的执行方法 1.3 实现指定执行方法的对象 1.4 是否重复执行 2 对象的内存管理及销毁 2.1 使用方法" invalidate "进行停止 2.2 将对象设置为" nil " 2.3 特别是在返回到其他视图控制器的时候,要在方法" -

iOS中延时执行的几种方式比较及汇总

前言 在开发过程中,我们有时会希望把一些操作封装起来延迟一段时间后再执行.本文列举了四种延时执行某函数的方法及其一些区别.假如延时1秒时间执行下面的方法. - (void)delayMethod { NSLog(@"execute"); } 1.performSelector方法 这是iOS中常用的一种延迟执行方法. //不带参数 [self performSelector:@selector(delayDo:) withObject:nil afterDelay:1.0f]; //带

iOS中使用schema协议调用APP和使用iframe打开APP的例子

在iOS中,需要调起一个app可以使用schema协议,这是iOS原生支持的,并且因为iOS系统中都不能使用自己的浏览器内核,所以所有的浏览器都支持,这跟android生态不一样,android是可以自己搞内核的,但是iOS不行. 在iOS中提供了两种在浏览器中打开APP的方法:Smart App Banner和schema协议. Smart App Banner 即通过一个meta 标签,在标签上带上app的信息,和打开后的行为,例如:app-id之类的,代码形如: 复制代码 代码如下: <m

IOS中的webView加载HTML

在日常开发中,我们为了效率会用到很多很多的WebView,比如在做某个明细页面的时候我们返回给你的可能是一个html字符串,我们就需要将当前字符串展示到webView上面,所以我们对HTML标签需要有一定的认识,下面我们来一起用html标签和JS写一个打地鼠游戏,这里我们主要讲解HTML标签的书写,只要如何和webView适配涉及到响应式布局我们下次讲解: 1.首先我们先新建一个html文件 2 完整html标签并且设置编码格式为UTF-8 3 在body里面增加十只老鼠图片,并且增加点击事件,

使用scrollTop()解决IOS中输入法遮挡输入框问题

经过测试,发现有的IOS浏览器上输入法会弹出遮挡输入框,网上很多都是介绍用以下方法 (function() { $('input').on('click', function () { var target = this; // 使用定时器是为了让输入框上滑时更加自然 setTimeout(function(){ target.scrollIntoView(true); },100); }); 但是由于本人对scrollIntoView的理解不够一直没有解决问题,后来用相同的思路使用scroll

iOS中UIAlertView3秒后消失的两种实现方法

一,效果图. 二,代码. - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. UIAlertView* alert = [[UIAlertView alloc]initWithTitle:nil message:@"此信息3秒后消失" delegate:nil cancelButtonTitle:nil ot

iOS中视频播放的基本方法总结

前言 本文总结了iOS中最常见的视频播放方法,不同的方法都各具特点,我希望能够总结它们的不同,方便在开发中选择合适的技术方案. Apple为我们提供了多种方法来实现视频播放,包括MPMoviePlayerController,MPMoviePlayerViewController,AVPlayer,AVPlayerViewController等.而值得注意的是,上述的MPMoviePlayerController与MPMoviePlayerViewController在iOS9.0之后被弃用.虽

IOS 中CALayer绘制图片的实例详解

IOS 中CALayer绘制图片的实例详解 CALayer渲染内容图层.与UIImageView相比,不具有事件响应功能,且UIImageView是管理内容. 注意事项:如何使用delegate对象执行代理方法进行绘制,切记需要将delegate设置为nil,否则会导致异常crash. CALayer绘制图片与线条效果图: 代码示例: CGPoint position = CGPointMake(160.0, 200.0); CGRect bounds = CGRectMake(0.0, 0.0

IOS 中CATextLayer绘制文本字符串

IOS 中CATextLayer绘制文本字符串 CATextLayer使用Core Text进行绘制,渲染速度比使用Web Kit的UILable快很多.而且UILable主要是管理内容,而CATextLayer则是绘制内容. CATextLayer的绘制文本字符串的效果如下: 代码示例: // 绘制文本的图层 CATextLayer *layerText = [[CATextLayer alloc] init]; // 背景颜色 layerText.backgroundColor = [UIC

iOS 中根据屏幕宽度自适应分布按钮的实例代码

下载demo链接:https://github.com/MinLee6/buttonShow.git 屏幕摆放的控件有两种方式,一种根据具体内容变化,一种根据屏幕宽度变化. 下面我分别将两个方式,用代码的方式呈现: 1:根据具体内容变化 // // StyleOneViewController.m // buttonShow // // Created by limin on 15/06/15. // Copyright © 2015年 信诺汇通信息科技(北京)有限公司. All rights