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

关于NSCache单例的并发安全性及nonisolated(unsafe)标记的合理性疑问(Swift 6)

关于NSCache单例的并发安全性及nonisolated(unsafe)标记的合理性疑问(Swift 6)

嘿,我来帮你把这个问题理清楚~

首先给你吃个定心丸:你的这个单例实现整体是线程安全的,不过nonisolated(unsafe)这个标记其实是多余的,甚至有点画蛇添足,咱们一步步说。

先聊NSCache的线程安全性

你说的没错,NSCache的所有公开API都是官方保证线程安全的,所以你对cache的读写操作,不管在多少个线程里调用,都不会出现数据竞争或者崩溃的情况,这部分你完全不用慌。

再看nonisolated(unsafe)的问题

Swift 6里默认的静态属性(比如你的shared)是自带并发隔离的,但你用nonisolated(unsafe)标记,相当于手动告诉编译器:“我知道这个属性的并发安全我自己兜着,你别管”。但实际上,你的shared是用static let定义的——Swift里static let的初始化本身就是原子性、线程安全的,多线程下只会初始化一次,根本不会有并发问题。所以这里完全没必要加nonisolated(unsafe),反而用了这个标记,之后如果有人修改单例内部逻辑,编译器可能不会再帮你做并发检查,反而埋下隐患。

正确的做法就是直接把这个标记删掉,写成:

public static let shared = CachedNumberFormatters()

就足够安全了。

最后说个小优化点:避免重复创建Formatter

你的cachedFormatter方法有个小竞态条件的问题:比如两个线程同时请求同一个decimalSeparator的Formatter,它们可能同时走到cache.object(forKey:)都返回nil,然后各自创建一个新的Formatter,最后都存入缓存。这不会导致崩溃,但会浪费内存创建重复对象。

如果要解决这个问题,只需要给这个方法加个内部锁就行,比如用NSLock:

public final class CachedNumberFormatters {
    public static let shared = CachedNumberFormatters()
    let cache = NSCache<NSString, NumberFormatter>()
    private let lock = NSLock() // 新增锁
    
    private init() {}

    public func simpleNumberFormatter(for decimalSeparator: String) -> NumberFormatter {
        return cachedFormatter(decimalSeparator: decimalSeparator)
    }

    func cachedFormatter(decimalSeparator: String) -> NumberFormatter {
        lock.lock()
        defer { lock.unlock() } // 确保锁一定会释放
        
        if let cachedObject = cache.object(forKey: decimalSeparator as NSString) {
            return cachedObject
        } else {
            let formatter = NumberFormatter()
            formatter.decimalSeparator = decimalSeparator
        
            cache.setObject(formatter, forKey: decimalSeparator as NSString)
            return formatter
        }
    }
}

加锁之后,就能保证同一时间只有一个线程能执行检查缓存和创建对象的逻辑,避免重复创建。

总结一下:

  • 你的实现本身线程安全,因为NSCache和static let单例初始化都自带线程安全保障
  • 别用nonisolated(unsafe),完全没必要,反而会降低编译器的并发检查力度
  • 加个锁可以解决重复创建对象的效率问题

备注:内容来源于stack exchange,提问作者ofun

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 09:09:37