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)
}
}
网友评论