Reputation: 17486
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
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
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