I am working on a live activity with a button that will do a network call when pressed on. I want to make sure that it can only be pressed once, and then ignored while the request is processed.
This is what I did: Since it seems that a new intent object is created for each button press, I am using a static synchroniser like this:
private var _isBusy: Bool = false
private var _timestamp: Date? = nil
private let queue: DispatchQueue
private let resetInterval: TimeInterval
init(resetInterval: TimeInterval = 60, queueLabel: String = "default.synchronizedBoolQueue") {
self.resetInterval = resetInterval
self.queue = DispatchQueue(label: queueLabel)
}
var isBusy: Bool {
get {
return queue.sync {
return _isBusy
}
}
set {
queue.sync {
_isBusy = newValue
}
}
}
func setIfNotBusy() -> Bool {
return queue.sync {
let now = Date()
if let timestamp = _timestamp {
if now.timeIntervalSince(timestamp) > resetInterval {
// Reset if it was more than the specified interval ago
_isBusy = false
_timestamp = nil
}
}
if !_isBusy {
_isBusy = true
_timestamp = now
return true
}
return false
}
}
func clearBusy() {
queue.sync {
_isBusy = false
_timestamp = nil
}
}
}
Then, in my intent I have:
private static let synchronizedBoolean = SynchronizedBoolean(queueLabel: "myIntent")
...
func perform() async throws -> some IntentResult {
NSLog("---LIVE perform() called")
if(!UserEventIntent.synchronizedBoolean.setIfNotBusy()){
NSLog("---LIVE Was already in progress!")
}else{
//doing intent logic here
UserEventIntent.synchronizedBoolean.clearBusy()
}
}
I am pretty new to Swift, so my hope is that someone more experienced than me could tell me if this a reasonable approach or if I'm missing anything?
A big question - let's say I go into the perform() method, and while I'm in there, the user presses the button and the intent is called again. I get the "already in progress", but the method must still provide a result. Will that effect the intent already in progress?
Thoughts much appreciated.