面试题答案
一键面试方式一:基于全局常量的单例
class Singleton {
static let shared = Singleton()
private init() {}
}
原理:
- 全局常量:
static let shared = Singleton()
定义了一个静态常量shared
,在整个应用程序生命周期中只会被初始化一次。这利用了 Swift 对全局常量的懒加载特性,当第一次访问shared
时,会创建Singleton
的实例。 - 私有构造函数:
private init()
将构造函数声明为私有,确保不能在类外部通过init
方法创建新的实例,从而保证了单例的唯一性。
方式二:基于 DispatchOnce
的单例
class Singleton {
static var shared: Singleton!
static let onceToken = DispatchOnceToken()
private init() {}
class func sharedInstance() -> Singleton {
DispatchQueue.once(token: &onceToken) {
shared = Singleton()
}
return shared
}
}
struct DispatchOnceToken {
private var _value: Int8 = 0
}
extension DispatchQueue {
private static var _onceTracker = [UInt: Int]()
class func once(token: inout DispatchOnceToken, block: () -> Void) {
let token = Unmanaged.passUnretained(&token).toOpaque()
if _onceTracker[UInt(bitPattern: token)] == nil {
_onceTracker[UInt(bitPattern: token)] = 0
block()
}
}
}
原理:
DispatchOnce
机制:通过DispatchQueue.once
方法(自定义扩展实现),确保block
中的代码只会被执行一次。once
方法使用一个内部的字典_onceTracker
来跟踪每个token
是否已经执行过block
。- 静态变量:
static var shared: Singleton!
定义了一个静态可选变量shared
用于存储单例实例。static let onceToken = DispatchOnceToken()
定义了一个DispatchOnceToken
实例,作为DispatchQueue.once
方法的标记。 - 私有构造函数:同样,
private init()
防止在类外部创建新的实例,保证单例的唯一性。在多线程环境下,DispatchQueue.once
能够确保单例实例在并发访问时的唯一性。