美文网首页iOS Developer
「取消」 GCD 延时队列

「取消」 GCD 延时队列

作者: SmallflyBlog | 来源:发表于2017-05-07 11:57 被阅读389次

在 iOS SDK 里面是无法取消提交的任务的,这里实现一个可以取消的例子。

void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

dispatch_after 的作用是在指定的队列,指定的时间执行任务,一般用在需要延时处理的场景。

然而它的延时并非完全的延时,延时任务在 dispatch_after 调用的时候,就已经提交给操作系统,之后操作系统在指定时间执行这个任务。所以这个任务在提交之后,执行之前,在某些时候即使修改内部的数据,也不会影响执行的结果。

例如:

    int i = 0;
    NSTimeInterval time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC));
    dispatch_after(time, dispatch_get_main_queue(), ^{
        printf("i = %d", i);
    });
    i = 2;
    
    // 输出: i = 0

在任务 block 中,捕获了当前 i 的瞬时值,之后对它进行修改,不会影响执行的结果。这是因为 i 作为局部变量,是分配在栈上的,在 block 还没有执行之前,i 已经出栈回收了。

如果一定想修改 block 内的 i 可以这样声明:

__block int i = 0;

这时输出的结果为 i = 2。

在变量前加上 __block 时,会将变量拷贝到堆上,而堆内存在线程之间可以共享。具体的细节可以参考 block 的实现原理

dispatch_after 在 Objective-C 中属于 C 的 API,而在 Swift 中被封装成对象,iOS8 之前是没有取消的功能的,在 iOS8 之后有加入 DispatchWorkItem 的概念,支持取消 block 的执行。

在 iOS8 之前其实我们可以自定义「取消」block 。

extension DispatchQueue {
    typealias Task = (_ cancel: Bool) -> Void
    func delay(_ time: TimeInterval, task: @escaping ()->()) -> Task? {
        
        func dispatch_later(_ block: @escaping ()->()) {
            let t = DispatchTime.now() + time
            self.asyncAfter(deadline: t, execute: block)
        }
        
        var closure: (()->Void)? = task
        var result: Task?
        
        let delayedClosure: Task = { cancel in
            if let internalClosure = closure {
                if cancel == false {
                    self.async(execute: internalClosure)
                }
            }
            closure = nil
            result = nil
        }
        
        result = delayedClosure
        
        dispatch_later {
            if let delayedClosure = result {
                delayedClosure(false)
            }
        }
        
        return result
    }
    
    func cancel(_ task: Task?) {
        task?(true)
    }
}

使用:

let task =  DispatchQueue.main.delay(3) {
    print("延迟三秒输出")
}
        
DispatchQueue.main.cancel(task)

点击这里查看 Objective-C 版本。

相关文章

  • 「取消」 GCD 延时队列

    在 iOS SDK 里面是无法取消提交的任务的,这里实现一个可以取消的例子。 void dispatch_afte...

  • 7.多线程基础(七)GCD加强

    1.GCD串行队列和并发队列 2.GCD延时执行 3.GCD线程组:(的作用) 4.GCD定时器: GCD的实现 ...

  • Swift小项目的细碎知识点

    一、GCD延时调用 HUD_DISMISS_TIME为延时执行的时间 二、GCD队列 三、判断一个对象是否为空 四...

  • GCD延时取消

    平常的开发中,经常要用到延时处理功能,一般比较实用的有2种方法,一是performSelector:withObj...

  • GCD编程

    今天谈论gcd编程的相关知识,gcd编程应该包涵的知识点有:g c d串行队列和并发队列,g c d的延时,线程组...

  • iOS-基础巩固-NSOperation

    NSBlockOperation GCD & NSOperation 对比 最大并发数 队列的取消、暂停、恢复 取...

  • swift 中 GCD简单使用

    1.GCD的使用 1.最常用的GCD模板//全局队列异步执行 2.延时调用 2.Any 和AnyObjectAny...

  • GCD延时任务取消

    1.dispatch_block_cancel iOS8之后可以调用dispatch_block_cancel来取...

  • 【面试必备】聊聊高性能延时队列应用

    【面试必备】聊聊高性能延时队列应用 延时队列的应用场景: 下单后,30分钟内未付款就自动取消订单等; 支付后,24...

  • iOS开发-延时执行

    1.GCD 注:dispatch_after方法本质是将任务延时添加到队列中,并不是延时执行任务,所以在对时间要求...

网友评论

    本文标题:「取消」 GCD 延时队列

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