取消Swift中的定时事件?
我想在一个事件的10秒内运行一段代码,但是我希望能够取消它,这样如果在这10秒钟之前发生了什么事,代码将在10秒钟后不会运行。
我一直在使用这个,但不能取消:
static func delay(delay:Double, closure:()->()) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)) ), dispatch_get_main_queue(), closure ) }
我怎样才能做到这一点?
试试这个(Swift 2.x,见下面的Swift 3的David的回答):
typealias dispatch_cancelable_closure = (cancel : Bool) -> () func delay(time:NSTimeInterval, closure:()->()) -> dispatch_cancelable_closure? { func dispatch_later(clsr:()->()) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(time * Double(NSEC_PER_SEC)) ), dispatch_get_main_queue(), clsr) } var closure:dispatch_block_t? = closure var cancelableClosure:dispatch_cancelable_closure? let delayedClosure:dispatch_cancelable_closure = { cancel in if let clsr = closure { if (cancel == false) { dispatch_async(dispatch_get_main_queue(), clsr); } } closure = nil cancelableClosure = nil } cancelableClosure = delayedClosure dispatch_later { if let delayedClosure = cancelableClosure { delayedClosure(cancel: false) } } return cancelableClosure; } func cancel_delay(closure:dispatch_cancelable_closure?) { if closure != nil { closure!(cancel: true) } } // usage let retVal = delay(2.0) { println("Later") } delay(1.0) { cancel_delay(retVal) }
从Waam的评论: dispatch_after – GCD在swift中?
Swift 3有DispatchWorkItem
:
let task = DispatchWorkItem { print("do something") } // execute task in 2 seconds DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2, execute: task) // optional: cancel task task.cancel()
更新Swift 3.0
设置执行select器
perform(#selector(foo), with: nil, afterDelay: 2)
foo方法将在2秒后调用
func foo() { //do something }
取消挂起的方法调用
NSObject.cancelPreviousPerformRequests(withTarget: self)
这应该工作:
var doIt = true var timer = NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector: Selector("doSomething"), userInfo: nil, repeats: false) //you have now 10 seconds to change the doIt variable to false, to not run THE CODE func doSomething() { if(doIt) { //THE CODE } timer.invalidate() }
我在一些项目中使用@sas的方法,不知何故,这不再有效,也许在Swift 2.1.1之后有所改变。 值复制而不是指针?
对我来说最简单的解决方法是:
var canceled = false delay(0.25) { if !canceled { doSomething() } }
出于某种原因, NSObject.cancelPreviousPerformRequests(withTarget: self)
不适合我。 我想到的一个工作是提出最多的循环,我会允许,然后使用该Int来控制函数是否被调用。
然后,我可以从我的代码中的其他任何地方设置currentLoop值,并停止循环。
//loopMax = 200 var currentLoop = 0 func loop() { if currentLoop == 200 { //do nothing. } else { //perform loop. //keep track of current loop count. self.currentLoop = self.currentLoop + 1 let deadline = DispatchTime.now() + .seconds(1) DispatchQueue.main.asyncAfter(deadline: deadline) { //enter custom loop parameters print("i looped") self.loop() } } }
然后在你的代码的其他地方,你可以
func stopLooping() { currentLoop = 199 //setting it to 199 allows for one last loop to happen. You can adjust based on the amount of loops you want to be able to do before it just stops. For instance you can set currentLoop to 195 and then implement a fade animation while loop is still happening a bit. }
这实际上是非常dynamic的。 例如,你可以看到currentLoop == 123456789,它会无限地运行(非常多),直到你把它设置到你的代码中的其他地方。 或者你甚至可以把它设置为一个String()或Bool(),如果你的需求不是像我一样的时间基础。