user482594
user482594

Reputation: 17486

In Swift, how can I guarantee that only 1 task runs/wait at the most of the time?

In Swift, I have a recursive function which I want it to be executed every minute. It looks something like below.

func someFunc() {
    // business logics...
    DispatchQueue.global().asyncAfter(deadline: .now() + 60) {
        self.someFunc()
    }
}

The thing is that this someFunc() can be initiated by multiple callers, but I only want to allow one instance of someFunc() running or waiting to be executed in the future.

What is the best way to guarantee that at most 1 someFunc() will be running or queued at any given timeeeee?

(I am using Swift 5.3)

Upvotes: 1

Views: 467

Answers (2)

Fabio Felici
Fabio Felici

Reputation: 2916

You can also use NSLock for this:

import PlaygroundSupport

let lock = NSLock()

func someFunc(msg: String) {
  guard lock.try() else { return }
  print(msg)
  DispatchQueue.global().asyncAfter(deadline: .now() + 5) {
    lock.unlock()
    someFunc(msg: msg)
  }
}

someFunc(msg: "call1")
someFunc(msg: "call2") // Ignored
someFunc(msg: "call3") // Ignored

PlaygroundPage.current.needsIndefiniteExecution = true

Upvotes: 3

Joakim Danielson
Joakim Danielson

Reputation: 52043

You can use a boolean to keep track of the function call is queued (assuming you're not calling someFunc() from different threads)

var isQueued = false
func someFunc() {
    if isQueued { return }
    // business logics...

    isQueued = true
    DispatchQueue.global().asyncAfter(deadline: .now() + 60) {
        self.isQueued = false
        self.someFunc()
    }
}

Example

class Example {
    var isQueued = false
    func someFunc(_ i: Int) {
        if isQueued { return }
        // business logics...
        if i > 500 {
            return
        }
        print(i)

        isQueued = true
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
            self.isQueued = false
            self.someFunc(i * 10)
        }
    }
}

let t = Example()
t.someFunc(1)
sleep(2)
t.someFunc(2)
sleep(1)
t.someFunc(3)
sleep(1)
t.someFunc(4)
sleep(1)
t.someFunc(5)

prints

1
10
100
4
40
400

Upvotes: 1

Related Questions