当需要实现类似“轮询”这种操作的时候,我们可能会希望有一个“被放缓了的” for 循环 —— 即当某次操作执行后,稍等一下再去执行下一次操作。这时有几种方法可以供我们使用,来实现这种效果,下面对比总结一下。
extension NSObject {
open func perform(_ aSelector: Selector, with anArgument: Any?, afterDelay delay: TimeInterval, inModes modes: [RunLoopMode])
open func perform(_ aSelector: Selector, with anArgument: Any?, afterDelay delay: TimeInterval)
open class func cancelPreviousPerformRequests(withTarget aTarget: Any, selector aSelector: Selector, object anArgument: Any?)
open class func cancelPreviousPerformRequests(withTarget aTarget: Any)
}
extension RunLoop {
open func perform(_ aSelector: Selector, target: Any, argument arg: Any?, order: Int, modes: [RunLoopMode])
open func cancelPerform(_ aSelector: Selector, target: Any, argument arg: Any?)
open func cancelPerformSelectors(withTarget target: Any)
}
这是系统提供的 API,其中最简单的第 2 个方法可以通过指定方法、参数、延迟时间来实现延迟调用。
优点:使用简单、自带根据 target 取消调用的机制 并且可以指定对象、方法来取消延迟调用 使得这个方法可以完成一些复杂的延迟调用机制 缺点:系统帮你自动完成了很多操作,使得它不像定时器(NSTimer)那样高度可控。
open class Timer : NSObject {
public /*not inherited*/ init(timeInterval ti: TimeInterval, invocation: NSInvocation, repeats yesOrNo: Bool)
open class func scheduledTimer(timeInterval ti: TimeInterval, invocation: NSInvocation, repeats yesOrNo: Bool) -> Timer
public /*not inherited*/ init(timeInterval ti: TimeInterval, target aTarget: Any, selector aSelector: Selector, userInfo: Any?, repeats yesOrNo: Bool)
open class func scheduledTimer(timeInterval ti: TimeInterval, target aTarget: Any, selector aSelector: Selector, userInfo: Any?, repeats yesOrNo: Bool) -> Timer
}
通过常见的定时器也可以实现延迟调用,把 repeats 参数置为 false,可以实现类似上面的 perform 的效果。
优点:定时器状态可控,可以重新赋值,可以查看是否 valid 等 缺点:对比上面的 perform 方法可以直接传参,这里想要传参的话只能曲线救国:
DispatchQueue.main.asyncAfter(wallDeadline: DispatchWallTime.now() + 1, execute: {
print("1 second after")
})
上面这段代码,可以在 1 秒之后,通过主线程执行 print。值得注意的是,设定时间的时候,有两种类型,一种是 DispatchTime,这个时间本质上是相对时间,它会在系统休眠的时候暂停,另外一种是 DispatchWallTime,这个时间正如其名,是“墙上的挂钟时间”,是绝对时间,比如你可能希望某一个任务准确地在x小时、x分钟、x秒之后执行,这段时间可能发生任何事情,这时推荐使用 DispatchWallTime.
神奇而伟大的 GCD 这里就不多做介绍了,有太多文章讲解它了 优点:执行的是闭包,可以随意传参 缺点:一旦开启,无法取消,只能提前在闭包里面添加严谨的逻辑判断了