Während die Verwendung von verzögert initialisierten Globals für eine einmalige Initialisierung sinnvoll sein kann, ist sie für andere Typen nicht sinnvoll. Es ist sehr sinnvoll, faul initialisierte Globals für Dinge wie Singletons zu verwenden. Es ist nicht sehr sinnvoll für Dinge wie das Bewachen eines Swizzle-Setups.
Hier ist eine Swift 3-Implementierung von dispatch_once:
public extension DispatchQueue {
private static var _onceTracker = [String]()
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token: String, block:@noescape(Void)->Void) {
objc_sync_enter(self); defer { objc_sync_exit(self) }
if _onceTracker.contains(token) {
return
}
_onceTracker.append(token)
block()
}
}
Hier ist ein Anwendungsbeispiel:
DispatchQueue.once(token: "com.vectorform.test") {
print( "Do This Once!" )
}
oder mit einer UUID
private let _onceToken = NSUUID().uuidString
DispatchQueue.once(token: _onceToken) {
print( "Do This Once!" )
}
Da wir uns derzeit in einer Zeit des Übergangs von Swift 2 zu 3 befinden, ist hier ein Beispiel für die Implementierung von Swift 2:
public class Dispatch
{
private static var _onceTokenTracker = [String]()
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token token: String, @noescape block:dispatch_block_t) {
objc_sync_enter(self); defer { objc_sync_exit(self) }
if _onceTokenTracker.contains(token) {
return
}
_onceTokenTracker.append(token)
block()
}
}