Skip to content

Instantly share code, notes, and snippets.

@kristopherjohnson
Created August 12, 2014 16:25
Show Gist options
  • Save kristopherjohnson/7522f92bb5c4b667d506 to your computer and use it in GitHub Desktop.
Save kristopherjohnson/7522f92bb5c4b667d506 to your computer and use it in GitHub Desktop.
Example of using dispatch_once() in Swift
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()
*/
@jereme
Copy link

jereme commented Aug 28, 2015

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.

@skyluca
Copy link

skyluca commented Oct 1, 2015

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
}

@toohotz
Copy link

toohotz commented Oct 31, 2015

Not necessarily totally wrong but as @jereme pointed out, this will execute every instantiation. @skyluca Static struct is the way to go for Swift 2.0 (similar to how Singleton's are done now as well).

@alickbass
Copy link

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.

@arielelkin
Copy link

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()
*/

@natebird
Copy link

natebird commented Apr 6, 2016

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()
}

@JKalash
Copy link

JKalash commented Jun 29, 2016

How about Swift 3.0? compiler nags about dispatch_once . Says should use lazily initialized globals instead.

@cybercent
Copy link

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
}

@tadassce
Copy link

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()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment