@@ -51,20 +51,41 @@ final class HeartbeatStorage: HeartbeatStorageProtocol {
51
51
// MARK: - Instance Management
52
52
53
53
/// Statically allocated cache of `HeartbeatStorage` instances keyed by string IDs.
54
- private static var cachedInstances : [ String : WeakContainer < HeartbeatStorage > ] = [ : ]
54
+ #if compiler(>=6)
55
+ // In Swift 6, this property is not concurrency-safe because it is
56
+ // nonisolated global shared mutable state. Because this target's
57
+ // deployment version does not support Swift concurrency, it is marked as
58
+ // `nonisolated(unsafe)` to disable concurrency-safety checks. The
59
+ // property's access is protected by an external synchronization mechanism
60
+ // (see `instancesLock` property).
61
+ private nonisolated ( unsafe) static var cachedInstances : [
62
+ String : WeakContainer < HeartbeatStorage >
63
+ ] = [ : ]
64
+ #else
65
+ // TODO(Xcode 16): Delete this block when minimum supported Xcode is
66
+ // Xcode 16.
67
+ private static var cachedInstances : [
68
+ String : WeakContainer < HeartbeatStorage >
69
+ ] = [ : ]
70
+ #endif // compiler(>=6)
71
+
72
+ /// Used to synchronize concurrent access to the `cachedInstances` property.
73
+ private static let instancesLock = NSLock ( )
55
74
56
75
/// Gets an existing `HeartbeatStorage` instance with the given `id` if one exists. Otherwise,
57
76
/// makes a new instance with the given `id`.
58
77
///
59
78
/// - Parameter id: A string identifier.
60
79
/// - Returns: A `HeartbeatStorage` instance.
61
80
static func getInstance( id: String ) -> HeartbeatStorage {
62
- if let cachedInstance = cachedInstances [ id] ? . object {
63
- return cachedInstance
64
- } else {
65
- let newInstance = HeartbeatStorage . makeHeartbeatStorage ( id: id)
66
- cachedInstances [ id] = WeakContainer ( object: newInstance)
67
- return newInstance
81
+ instancesLock. withLock {
82
+ if let cachedInstance = cachedInstances [ id] ? . object {
83
+ return cachedInstance
84
+ } else {
85
+ let newInstance = HeartbeatStorage . makeHeartbeatStorage ( id: id)
86
+ cachedInstances [ id] = WeakContainer ( object: newInstance)
87
+ return newInstance
88
+ }
68
89
}
69
90
}
70
91
@@ -88,7 +109,9 @@ final class HeartbeatStorage: HeartbeatStorageProtocol {
88
109
89
110
deinit {
90
111
// Removes the instance if it was cached.
91
- Self . cachedInstances. removeValue ( forKey: id)
112
+ _ = Self . instancesLock. withLock {
113
+ Self . cachedInstances. removeValue ( forKey: id)
114
+ }
92
115
}
93
116
94
117
// MARK: - HeartbeatStorageProtocol
0 commit comments