-
-
Save kristopherjohnson/7522f92bb5c4b667d506 to your computer and use it in GitHub Desktop.
import Foundation | |
var token: dispatch_once_t = 0 | |
func test() { | |
dispatch_once(&token) { | |
println("This is printed only on the first call to test()") | |
} | |
println("This is printed for each call to test()") | |
} | |
for _ in 0..<4 { | |
test() | |
} | |
/* Output: | |
This is printed only on the first call to test() | |
This is printed for each call to test() | |
This is printed for each call to test() | |
This is printed for each call to test() | |
This is printed for each call to test() | |
*/ |
This code is totally wrong and will not work, at least in swift 2.0. In this way, dispatch_once, in general, will be called multiple times.
The right way to do it is:
struct Static {
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
// CODE TO BE EXECUTED ONCE
}
BTW, if we take a good look at the documentation https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/
Apple says that variables of this dispatch_once_t must have global or static scope. The result of using this type with automatic or dynamic allocation is undefined.
I don't understand why that code makes sense! The token is a variable, and nothing guarantees it won't be reset:
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()
*/
The Swift 2.x version of this should look like the following:
import Foundation
struct Static {
static var dispatchOnceToken: dispatch_once_t = 0
}
func test() {
dispatch_once(&Static.dispatchOnceToken) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
for _ in 0..<4 {
test()
}
How about Swift 3.0? compiler nags about dispatch_once . Says should use lazily initialized globals instead.
Swift 3 extension:
import Foundation
public extension DispatchQueue {
private static var _onceTracker = [String]()
public class func once(token: String, block:(Void)->Void) {
objc_sync_enter(self); defer { objc_sync_exit(self) }
if _onceTracker.contains(token) {
return
}
_onceTracker.append(token)
block()
}
}
Usage:
DispatchQueue.once(token: "your-unique-token") {
// code to run once
}
In Swift 3 something like this:
class Test {
static let once: Void = {
print("only first time")
}()
func hi() {
Test.once
print("every time")
}
}
let test = Test()
for i in 0..<3 {
test.hi()
}
For clarity, your code example will execute the code once for every instance. If you want to use this on a singleton, your once Token must be a static member.