how to stop a dispatchQueue in swift
I'm not sure if there are best practices here, but I would consider doing what you are doing with a Timer rather than the DispatchQueue.
class GifClass: UIViewController {
@IBOutlet weak var gifImage: UIImageView!
@IBOutlet weak var skipButton: UIButton!
var timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
gifImage.loadGif(name: "promed")
timer = Timer.scheduledTimer(timeInterval: 11, target: self, selector: #selector(timerAction), userInfo: nil, repeats: false)
}
@objc func timerAction() {
performSegue(withIdentifier: "introLogin", sender: self)
}
@IBAction func skip(_ sender: Any) {
timer.invalidate()
performSegue(withIdentifier: "introLogin", sender: self)
}
}
Cancel a timed event in Swift?
Try this (Swift 2.x, see David's answer below for Swift 3):
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)
}
From Waam's comment here: dispatch_after - GCD in swift?
How does DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) work in Swift 3?
OK, I found the answer to my own question in this thread:
How do I write dispatch_after GCD in Swift 3?
Apparently there is an override of the +
operator that takes a DispatchTime
and a double, treats the double as decimal seconds, and returns a resulting DispatchTime
.
Create several DispatchQueue.main.asyncAfter methods at once in Swift 3
You can fix this by creating local variables:
@IBAction func playButtonPressed(_ sender: Any) {
var index = 0.0
var i = 0
var j = 0
while i < sites.count {
while j < sites[i].count {
let day = i
let site = j
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0 * index) {
self.plot(day: day, site: site)
}
j += 1
index += 1
}
j = 0
i += 1
}
}
Or, as pointed out by Martin R in Pass value to closure?, you can "capture" these variables:
@IBAction func playButtonPressed(_ sender: Any) {
var index = 0.0
var i = 0
var j = 0
while i < sites.count {
while j < sites[i].count {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0 * index) { [i, j] in
self.plot(day: i, site: j)
}
j += 1
index += 1
}
j = 0
i += 1
}
}
Or, personally, I'd probably use for
loops to clean this up a bit:
@IBAction func playButtonPressed(_ sender: Any) {
var delay = 0.0
for i in 0 ..< sites.count {
for j in 0 ..< sites[i].count {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [i, j] in
self.plot(day: i, site: j)
}
delay += 1
}
}
}
Resetting DispatchQueue each time a tap occurs
It would be simpler to use a Timer, because that is something that is easy to cancel (invalidate
) and start the timer again (Timer.scheduledTimer
) if the user taps before the Timer fires at the end of 5 seconds.
For example, that is how my LinkSame app works. There is a 10-second "move" timer. If the user doesn't make a valid move within 10 seconds of the previous move, the user loses 10 points and the timer starts over. If the user does make a valid move within 10 seconds of the previous move, the user gets a score based on where we are in the timer and the timer starts over. That is all accomplished with a Timer.
Related Topics
Variable Captured by Closure Before Being Initialized
Swift How to Cast from Int? to String
How to Share Both Image and Text Together in Swift
Swift Delegate for a Generic Class
How to Get the Centre of the View
Swift Draw Shadow to a Uibezier Path
Using Foreach with a an Array of Bindings (Swiftui)
Avoid Consecutive "If Let" Declarations in Swift
How to Open Url in Safari and the Get Back to the App Under Uitests in Xcode 7
How in Swift to Convert Int16 to Two Uint8 Bytes
Detect Ethernet/Wifi Network Change
Difference Between Packed VS Normal Data Type
How to Set Inputview for Textfield in Swiftui
Scenekit -- How to Get Animations for a .Dae Model
Difference Between Swift's Hash and Hashvalue
Swift - How to Save Audio from Avaudioengine, or from Audioplayernode? If Yes, How