Остановить отправку_после

Я использую анимацию для указания подсказки, чтобы помочь взаимодействию с задержкой, используя эти:

 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()

    }

Но мне нужно остановить этот процесс задержки, если перед запуском анимации пользователь коснется экрана.

Ответ 1

iOS 8 и OS X Yosemite представили dispatch_block_cancel, которые позволяют вам отменить их до того, как они начнут выполнять

Вы объявляете одну переменную в классе следующим образом:

var block: dispatch_block_t?

Init 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!)

Ответ 2

Swift 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
    }
}

Ответ 3

Вот общее решение, которое я написал, чтобы отменить dispatch_after в Swift:

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()
}

Ответ 4

Вы можете создать логическую переменную 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
}