2015-02-05 45 views
12

我用一個動畫指定一個提示,以幫助使用這些與延遲的相互作用:停止dispatch_after

let delay = 1.8 * Double(NSEC_PER_SEC) 
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay)) 
    dispatch_after(time, dispatch_get_main_queue()) { 
     //call the method which have the steps after delay. 

     self.rain.alpha = 0 

     UIView.animateWithDuration(5, animations: { 

      self.rain.alpha = 1 

     }) 

     self.tip.startAnimating() 

    } 

但是,我需要的,如果,動畫開始前,用戶觸摸屏幕來停止這種延遲的過程。

+0

的可能的複製[取消在夫特定時事件?](http://stackoverflow.com/questions/28359768/cancel-a-timed-event- in-swift) – 2016-09-25 07:48:23

回答

3

您可以創建一個布爾變量shouldCancelAnimation並在dispatch_after塊內對其進行測試,以防止執行動畫。

var shouldCancelAnimation = false // property of class 

func runAnimation() 
{ 
    let delay = 1.8 * Double(NSEC_PER_SEC) 
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay)) 
    dispatch_after(time, dispatch_get_main_queue()) { 

     if !self.shouldCancelAnimation 
     { 
      self.rain.alpha = 0 
      UIView.animateWithDuration(5, animations: { 
       self.rain.alpha = 1 
      }) 

      self.tip.startAnimating() 
     } 
     self.shouldCancelAnimation = false 
    } 
} 

func viewWasTouched() // This could be touches began or taprecognizer event 
{ 
    shouldCancelAnimation = true 
} 
+0

如果您在延遲時間之前再次調用runAnimation,這將不起作用。 – ayalcinkaya 2016-01-10 15:24:55

+0

一個更通用的方法:http://stackoverflow.com/a/38470235/856925 – 2016-07-19 23:45:25

6

這是我寫給取消斯威夫特一個dispatch_after一個通用的解決方案:

typealias cancellable_closure = (() ->())? 

func dispatch_after(#seconds:Double, queue: dispatch_queue_t = dispatch_get_main_queue(), closure:()->()) -> cancellable_closure { 
    var cancelled = false 
    let cancel_closure: cancellable_closure = { 
     cancelled = true 
    } 

    dispatch_after(
     dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC))), queue, { 
      if !cancelled { 
       closure() 
      } 
     } 
    ) 

    return cancel_closure 
} 

func cancel_dispatch_after(cancel_closure: cancellable_closure) { 
    cancel_closure?() 
} 

用法:

let doSomethingLater = dispatch_after(seconds: 3.0) { 
    something() 
} 
.... 
if shouldCancelForSomeReason { 
    cancel_dispatch_after(doSomethingLater) 
} 

默認情況下它運行在主隊列,但你可以通過在一個參數讓它在另一個隊列上運行:

let doSomethingLater = dispatch_after(seconds: 3.0, queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { 
    something() 
} 
37

的iOS 8和OS X的優勝美地介紹dispatch_block_cancel,使您可以取消他們開始之前,他們執行

您在類中聲明一個變量,如下所示:

var block: dispatch_block_t? 

初始化block變量,併爲其提供在dispatch_after

block = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS) { 
    print("I executed") 
} 
let time: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(5 * NSEC_PER_SEC)) 
dispatch_after(time, dispatch_get_main_queue(), block!) 

之後,你可以如下取消:

dispatch_block_cancel(block!) 
+5

你真的應該upvoted更多;沒有足夠的人知道這個... – Frizlab 2016-07-18 10:19:51

+0

在Swift 4代碼它說:'dispatch_block_t'在Swift中不可用 – 2017-12-12 16:00:54

+0

這是一個很好的答案,但需要更新Swift。使用下面的APIS:'var block = DispatchWorkItem {// do stuff}'然後'DispatchQueue.global()。async(execute:block)'最後'block.cancel()' – 2017-12-29 00:07:13

14

夫特3.0實施例DispatchQueue取消或停止

var dispatchQueue: DispatchQueue? 
var dispatchWorkItem: DispatchWorkItem? 

func someOnClickButtonStart() { 
    self.dispatchQueue = DispatchQueue.global(qos: .background) // create queue 
    self.dispatchWorkItem = DispatchWorkItem { // create work item 
     // async code goes here 
    } 
    if self.dispatchWorkItem != nil { 
     self.dispatchQueue?.asyncAfter(
      deadline: .now() + .seconds(1), 
      execute: self.dispatchWorkItem! 
     ) // schedule work item 
    } 
} 

func someOnClickButtonCancel() { 
    if let dispatchWorkItem = self.dispatchWorkItem { 
     dispatchWorkItem.cancel() // cancel work item 
    } 
} 
+0

我要給你upvote,因爲這最終奏效。但是這個代碼需要一些工作。 – dfmuir 2017-03-30 23:05:27