早在Swift 3的时候,dispatch_once
就被苹果废弃了,并且推荐使用懒初始化全局变量方案代替。
官方推荐的解决办法:
The free function dispatch_once is no longer available in Swift. In Swift, you can use lazily initialized globals or static properties and get the same thread-safety and called-once guarantees as dispatch_once provided. Example:
let myGlobal = { … global contains initialization in a call to a closure … }() _ = myGlobal // using myGlobal will invoke the initialization code only the first time it is used.
下面来介绍4种实现dispatch_once
的只调用一次的方法
一. 带立即执行闭包初始化器的全局变量
let dispatchOnce: () = {
print("dispatchOnce-------")
}()
/// 使用Aspects做交换: 用一个全局的常量来实现的dispatchOnce效果
let doSwizzles: () = {
print("doSwizzles----")
let oriSel1 = #selector(UIViewController.viewWillAppear(_:))
let wrappedBlock: @convention(block) (AspectInfo, Bool) -> Void = { aspectInfo, _ in
print("wrappedBlock---")
}
_ = try? UIViewController.aspect_hook(oriSel1, with: AspectOptions.positionBefore, usingBlock: wrappedBlock)
}()
// 之后在合适的时机使用变量,比如:
_ = dispatchOnce
二、全局常量
let foo = ViewController()
三、类,结构,枚举中的静态属性
class Person22 {
static var dog = Dog()
}
四、封装一个once函数
public extension DispatchQueue {
private static var _onceTracker = [String]()
/// 函数只被执行一次
static func once(token: String, block: () -> ()) {
// objc_sync_enter + objc_sync_exit 相当于OC中的@sychronize() {}
objc_sync_enter(self)
defer {
objc_sync_exit(self)
}
if _onceTracker.contains(token) {
return;
}
_onceTracker.append(token)
block()
}
}