The answers I've seen so far (1, 2, 3) recommend using GCD's dispatch_once
thus:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
But wait a minute. token
is a variable, so I could easily do this:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
token = 0
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
This is printed only on the first call to test()
This is printed for each call to test()
So dispatch_once
is of no use if we I can change the value of token
! And turning token
into a constant is not straightforward as it needs to of type UnsafeMutablePointer<dispatch_once_t>
.
So should we give up on dispatch_once
in Swift? Is there a safer way to execute code just once?
You can run the Swift REPL from the command line and enter Swift code directly into it. Whenever you enter valid Swift code in the REPL, it will immediately compile and run it. Lets play around with the Swift REPL a bit. You can access previous lines that you've entered using $R0 etc.
You can use one like this: var timer = NSTimer() override func viewDidLoad() { scheduledTimerWithTimeInterval() } func scheduledTimerWithTimeInterval(){ // Scheduling timer to Call the function "updateCounting" with the interval of 1 seconds timer = NSTimer.
A man went to the doctor, and said "Doctor, it hurts when I stamp on my foot". The doctor replied, "So stop doing it".
If you deliberately alter your dispatch token, then yes - you'll be able to execute the code twice. But if you work around the logic designed to prevent multiple execution in any way, you'll be able to do it. dispatch_once
is still the best method to ensure code is only executed once, as it handles all the (very) complex corner cases around initialisation and race conditions that a simple boolean won't cover.
If you're worried that someone might accidentally reset the token, you can wrap it up in a method and make it as obvious as it can be what the consequences are. Something like the following will scope the token to the method, and prevent anyone from changing it without serious effort:
func willRunOnce() -> () {
struct TokenContainer {
static var token : dispatch_once_t = 0
}
dispatch_once(&TokenContainer.token) {
print("This is printed only on the first call")
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With