purplePanda
purplePanda

Reputation: 87

Pause Loop Iteration in Swift

I currently have a loop like this, but I realize that using sleep is not the way to do this. I want it to take 60 seconds to go next iteration in the loop. How might I approach this in a better way? Thanks!

for count in 0...60 {
   if arrayOfOptions.contains(count) {
      // play a sound.     
   }
   sleep(1) // pause the loop for 1 second before next iteration
}

Upvotes: 2

Views: 3576

Answers (5)

T. Benjamin Larsen
T. Benjamin Larsen

Reputation: 6383

I agree with Ahmad F that recursion is probably the way to go. My example is solution is in the same ballpark, with the difference that I pass the index to avoid having a class-wide variable just for this purpose. (+ some minor stylistical differences).

func playSound(fromIndex index: Int = 0)) {
    guard index < arrayOfOptions.count else { return } // safety first
    if arrayOfOptions.contains(index) {
        // play a sound
    }
    guard index <= 60 else { return }

    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
        self.playSound(fromIndex: index+1)
    }
}

This would simply be started with playSound()

@PurplePanda If the idea is to run through the entire array, changing the guard statement to guard index < arrayOfOptions.count else { return } would be more sensible. That is also why I have added the initial guard statement, since there is no technical reason to assume the array isn't empty...

It might easily make sense to expand upon this and having the function receive the array as well, but that depends on your specific requirements obviously...

Upvotes: 0

Zahurafzal Mirza
Zahurafzal Mirza

Reputation: 288

Here's a function to which delays the execution for the specified amount of time.

//MARK: Delay function

func delay(_ delay:Double, closure:@escaping ()->()) {
    DispatchQueue.main.asyncAfter(
        deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
}

and you use the function like so :

delay(2)  //Specify the amount of time - In your case "1" second
{
      //Put the delayed code here
}

Hope this helps you out.

Upvotes: 0

Manish Mahajan
Manish Mahajan

Reputation: 2082

Call this function from for loop:-

//MARK: Delay func 
func delay(_ delay:Double, closure:@escaping ()->()) {
    DispatchQueue.main.asyncAfter(
        deadline: DispatchTime.now() + Double(Int64(delay * 
    Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
}

Example :-

for() {
    //your code
    self.delay(2) {

    }
    //Your code
}

Upvotes: -1

Ahmad F
Ahmad F

Reputation: 31645

You could achieve thus by following the recursion approach, for instance:

var count = 0
func playSound(delayInSeconds: Int) {
    // here you can do your functionality
    print("\(count): do my thing")

    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(delayInSeconds)) {
        if self.count < 61 {
            self.count += 1
            self.playSound(delayInSeconds: delayInSeconds)
        }
    }
}

thus you call it as:

playSound(delayInSeconds: 2)

Upvotes: 0

Oren
Oren

Reputation: 61

I would suggest using a Timer:

  1. Move the loop to a function

    func playSound(for value: Int, in array: [Int]) {
        if array.contains(value) {
            playSound()
        }
    }
    
  2. Create a timer:

    Timer.scheduledTimer(withTimeInterval: 1.0, 
                         repeats: true) { [weak self] _ in
                             guard let array = self?.array, let index = self?.currentIndex else { return }
                             self?.playSound(for: index, in: array)
                             self?.index = index + 1
                         })
    

Upvotes: 2

Related Questions