MST
星途 面试题库

面试题:Swift 中实现单例模式的常见方式及原理

在 Swift 中,请阐述实现单例模式的至少两种常见方式,并详细说明每种方式背后的原理,包括涉及到的语言特性等。
29.5万 热度难度
编程语言Swift

知识考点

AI 面试

面试题答案

一键面试

方式一:基于全局常量的单例

class Singleton {
    static let shared = Singleton()
    private init() {}
}

原理

  1. 全局常量static let shared = Singleton() 定义了一个静态常量 shared,在整个应用程序生命周期中只会被初始化一次。这利用了 Swift 对全局常量的懒加载特性,当第一次访问 shared 时,会创建 Singleton 的实例。
  2. 私有构造函数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()
        }
    }
}

原理

  1. DispatchOnce 机制:通过 DispatchQueue.once 方法(自定义扩展实现),确保 block 中的代码只会被执行一次。once 方法使用一个内部的字典 _onceTracker 来跟踪每个 token 是否已经执行过 block
  2. 静态变量static var shared: Singleton! 定义了一个静态可选变量 shared 用于存储单例实例。static let onceToken = DispatchOnceToken() 定义了一个 DispatchOnceToken 实例,作为 DispatchQueue.once 方法的标记。
  3. 私有构造函数:同样,private init() 防止在类外部创建新的实例,保证单例的唯一性。在多线程环境下,DispatchQueue.once 能够确保单例实例在并发访问时的唯一性。