dispatch_after 取消操作

2020-12-07  本文已影响0人  乡下秋草

iOS并没有提供官方的dispatch_after 的取消方法,但可以通过block封装完成需求。

代码来自某不知名大神,注释按自己理解写的。

import UIKit

class HomeViewController: UIViewController {

    //原理:通过将操作block封装两层,定时器时间到达之后,执行第一层,并且立即执行第二层。如果想要取消第二层,则将第二层的代码块置为nil
    typealias Task = (_ cancel : Bool) -> ()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.orange
        let task = delay(3) {
            print("3秒后执行")
        }
        sleep(1)
        cancel(task)
    }
    
    @discardableResult
    func delay(_ time:TimeInterval, task:@escaping () -> ()) -> Task? {
        //定义了一个延迟函数,time秒之后调用block
        func dispatch_later(_ block:@escaping () -> ()) {
            DispatchQueue.main.asyncAfter(
                deadline: DispatchTime.now() + Double(Int64(time * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC),
                execute: block)
        }
        
        //将task block赋值给closure
        var closure: (() -> Void)? = task
        var result: Task?
        // Task 代码块的实现,别处通过delayedClosure(bool)调用此函数
        let delayedClosure: Task = { cancel in
            //将closure赋值给internalClosure
            if let internalClosure = closure {
                //如果传过来的值为false,则说明不取消,立马执行internalClosure,也即closure,
                //也即task
                if (cancel == false){
                    //此处将立即执行,传过来的代码块
                    DispatchQueue.main.async(execute: internalClosure)
                }
            }
            //如果传过来的值为true,则将代码块内容为nil,result为nil
            closure = nil
            result = nil
        }
        result = delayedClosure
        //此处调用开始的dispatch_later函数,当执行完成之后调用delayedClosure(false)
        dispatch_later {
            print("还是执行了")
            if let delayedClosure = result {
                delayedClosure(false)
            }
        }
        
        return result
    }
    
    func cancel(_ task:Task?) {
        task?(true)
    }

}

上一篇下一篇

猜你喜欢

热点阅读