Per the documentation:
You can add, remove, and query items in the cache from different threads without having to lock the cache yourself.
Does this mean that if you limited usage to just add, remove, and query you could consider NSCache
sendable?
Per the documentation:
You can add, remove, and query items in the cache from different threads without having to lock the cache yourself.
Does this mean that if you limited usage to just add, remove, and query you could consider NSCache
sendable?
1 Answer
Reset to default 1An NSCache
is safe to access from any thread, but the values themselves are only safe to access across isolation domains if they are Sendable
(otherwise, you could accidentally use an NSCache
to silently transfer values across isolation domains, which isn't valid to do). Ideally, this would be expressed as
extension NSCache: Sendable where KeyType: Sendable, ObjectType: Sendable {}
to help prevent accidentally passing around NSCache
instances containing non-Sendable
types.
Except, this isn't possible to express, because NSCache
isn't truly generic in the Swift sense — KeyType
and ObjectType
don't really exist at runtime. The above extension yields
Type 'NSCache<KeyType, ObjectType>' cannot conditionally conform to protocol 'Sendable' because the type uses the Objective-C generics model
And since it's not safe to unconditionally mark NSCache: @unchecked Sendable
, Sendable
conformance was likely left off altogether.
While you can add your own @retroactive @unchecked Sendable
conformance to NSCache
(if you can guarantee you never place non-Sendable
types in a cache), it's likely safer to wrap in a type you control yourself which is generic in the Swift sense, and can be correctly marked as Sendable
:
import Foundation
struct SendableCache<Key: AnyObject, Value: AnyObject> {
let cache: NSCache<Key, Value>
}
extension SendableCache: @unchecked Sendable where Key: Sendable, Value: Sendable {}
: Sendable
. – Alexander Commented Mar 20 at 22:26