You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 3中dispatch_once代码转换求助:遇‘dispatch_once不可用’报错

解决Swift 3中dispatch_once不可用的问题

嘿,这个问题我太熟悉了!Swift 3开始苹果正式弃用了dispatch_once,因为Swift语言本身已经提供了更简洁、更安全的方式来实现“只执行一次”的逻辑,不需要再依赖GCD的C API啦。我给你几个实用的替代方案:

方案1:利用Swift静态属性的懒加载特性(推荐)

Swift的静态属性默认是线程安全的,而且只会在第一次被访问时初始化,完美替代dispatch_once的功能。把你的一次性执行代码放到一个静态属性的闭包里就行:

func willRunOnceCoach() {
    struct TokenContainer {
        static let runOnce: Void = {
            print("This is printed only on the first call")
            self.createCochMark()
        }()
    }
    // 第一次调用时会触发闭包执行,后续调用只会访问已经初始化好的静态属性,不会重复执行
    _ = TokenContainer.runOnce
}

原理说明:

  • 嵌套结构体TokenContainer的静态属性runOnce是Void类型,闭包会在第一次访问runOnce时执行
  • Swift保证静态属性的初始化是原子性的,完全不用担心线程安全问题
  • 后续调用这个方法时,runOnce已经初始化完成,只会做一次简单的取值操作,不会重复执行闭包里的代码

方案2:类/全局级别的一次性初始化

如果你的一次性逻辑是类级别的(比如初始化类的全局配置),可以直接把代码放到类的静态属性里:

class CoachManager {
    // 类级别的一次性初始化代码
    static let classSetup: Void = {
        print("CoachManager setup runs only once")
        // 这里放类的全局初始化逻辑
    }()
    
    func doSomething() {
        // 触发一次性初始化
        _ = CoachManager.classSetup
    }
}

方案3:手动加锁实现(不推荐,仅作参考)

如果你习惯了GCD的思路,也可以用锁+标志位来实现,但代码会更繁琐,不如静态属性优雅:

func willRunOnceCoach() {
    // 静态变量保存执行状态,只会初始化一次
    static var hasExecuted = false
    static let executionLock = NSLock()
    
    // 加锁保证线程安全
    executionLock.lock()
    defer { executionLock.unlock() }
    
    // 已经执行过就直接返回
    guard !hasExecuted else { return }
    
    // 标记为已执行
    hasExecuted = true
    
    // 执行你的逻辑
    print("This is printed only on the first call")
    self.createCochMark()
}

总结

优先用方案1,这是Swift官方推荐的方式,代码简洁、线程安全,完全符合Swift的语言设计理念。

内容的提问来源于stack exchange,提问作者naveen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:38:55