MiddleКодЧастоЕщё не отвечали
Преобразуйте class общего кэша с блокировкой в actor
Кэш ниже сериализует доступ через NSLock. Преобразуйте его в actor и опишите, что меняется в каждом месте вызова.
Требования:
- Уберите ручную блокировку; полагайтесь на изоляцию actor'а.
- Сохраните один общий экземпляр с тем же API
value(for:)/store(_:for:). - Укажите, что должны изменить вызывающие и какая возможность теряется.
final class ImageCache {
private var storage: [String: Data] = [:]
private let lock = NSLock()
func value(for key: String) -> Data? {
lock.lock(); defer { lock.unlock() }
return storage[key]
}
func store(_ data: Data, for key: String) {
lock.lock(); defer { lock.unlock() }
storage[key] = data
}
}
Напишите версию на actor.
Сделайте тип actor и удалите NSLock — компилятор сам сериализует доступ. Каждое место вызова становится async, поэтому к кэшу обращаются через await. Теряете синхронный доступ: не-async код больше не может прочитать кэш напрямую без Task.
- ✗Думают, что места вызова остаются синхронными после перехода на
actor - ✗Оставляют
NSLockвнутри actor'а, будто он всё ещё нужен - ✗Считают, что
actorпревращает кэш в значимый тип
- →Как прочитать кэш actor'а из синхронного колбэка UIKit?
- →Почему компилятор делает каждое внешнее чтение кэша
await?
Замените class на actor и уберите NSLock — actor сам сериализует доступ:
actor ImageCache {
private var storage: [String: Data] = [:]
func value(for key: String) -> Data? { storage[key] }
func store(_ data: Data, for key: String) { storage[key] = data }
}
// место вызова
let data = await cache.value(for: key)
await cache.store(bytes, for: key)
Каждый вызов теперь async и требует await из async-контекста. Синхронного доступа больше нет: из обычного метода придётся оборачивать обращение в Task { await ... }.