swift中的线程安全单例

我有和应用程序有一个单一的存储整个应用程序的信息.但是,当使用来自不同线程的单例时,这会产生一些数据争用问题.

这里有一个非常虚拟和简单化的问题版本:

独生子

class Singleton {
    static var shared = Singleton()

    var foo: String = "foo"
}

单例的使用(为简单起见,来自AppDelegate)

class AppDelegate: UIResponder,UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        DispatchQueue.global().async {
            var foo = Singleton.shared.foo // Causes data race
        }

        DispatchQueue.global().async {
            Singleton.shared.foo = "bar"   // Causes data race
        }

        return true
    }
}

有没有办法确保单例是线程安全的,所以它可以在应用程序的任何地方使用,而不必担心你在哪个线程?

这个问题不是Using a dispatch_once singleton model in Swift的重复(因为我理解正确),因为它们正在解决访问单例对象本身的问题,但不能确保其属性的读取和写入是安全地完成的.

感谢@rmaddy的评论指出了我正确的方向,我能够解决问题.

为了使Singleton线程的属性foo安全,需要修改如下:

class Singleton {
    static var shared = Singleton()
    private let internalQueue = DispatchQueue(label: "SingletionInternalQueue",qos: .default,attributes: .concurrent)

    private var _foo: String = "aaa"

    var foo: String {
        get {
            return internalQueue.sync { _foo }
        }
        set (newState) {
            internalQueue.async(flags: .barrier) { self._foo = newState }
        }
    }

    func setup(string: String) {
        foo = string
    }
}

线程安全是通过使用计算属性foo来完成的,该属性使用internalQueue来访问“real”_foo属性.

此外,为了获得更好的性能,internalQueue被创建为并发.这意味着在写入属性时需要添加barrier标志.

屏障标志的作用是确保在队列中所有先前计划的工作项完成时执行工作项.

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...