Stop dispatch_after

后端 未结 5 766
迷失自我
迷失自我 2020-12-24 03:36

I use an animation for specify a tip to help the interaction with delay using these:

 let delay = 1.8 * Double(NSEC_PER_SEC)
    let time = dispatch_time(DIS         


        
相关标签:
5条回答
  • 2020-12-24 03:46

    Swift 3.0 Example DispatchQueue cancel or stop

    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 讨论(0)
  • 2020-12-24 03:50

    You can create a boolean variable shouldCancelAnimation and test it inside the dispatch_after block to prevent the execution of your animation.

    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 讨论(0)
  • 2020-12-24 03:58

    iOS 8 and OS X Yosemite introduced dispatch_block_cancel that allow you to cancel them before they start executing

    You declare one variable in class as follows:

    var block: dispatch_block_t?
    

    Init block variable and provide it in 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!)
    

    After that you can cancel it as follows:

    dispatch_block_cancel(block!)
    
    0 讨论(0)
  • 2020-12-24 04:01

    Just sharing, in Swift 4.x, I do this:

    var block: DispatchWorkItem?

    self.block = DispatchWorkItem { self.go(self) }
    
    // execute task in 2 seconds
    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3), execute: self.block!)
    

    and then to cancel the block, self.block?.cancel()

    Try this sample project:

    import UIKit
    
    class ViewController: UIViewController {
    
        var block: DispatchWorkItem?
    
        @IBAction func go(_ sender: Any) {
            self.block?.cancel()
            let vc2 = VC2()
            self.navigationController?.pushViewController(vc2, animated: true)
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.view.backgroundColor = .white
        }
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
    
            self.block = DispatchWorkItem { self.go(self) }
    
            // execute task in 2 seconds
            DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3), execute: self.block!)
        }    
    }
    
    
    class VC2: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.view.backgroundColor = .green
        }
    }
    
    0 讨论(0)
  • 2020-12-24 04:03

    Here's a general solution I wrote to cancel a dispatch_after in 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?()
    }
    

    Usage:

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

    By default it runs on the main queue, but you can pass in a parameter for it to run on another queue:

    let doSomethingLater = dispatch_after(seconds: 3.0, queue: dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
        something()
    }
    
    0 讨论(0)
提交回复
热议问题