Для дискового кеша произвольный T нужно уметь сериализовать. Один вариант — ограничить T протоколом Codable и хранить JSON по безопасному имени файла.
// Записывает `data` в файл с именем `file`.
Для дискового кеша произвольный T нужно уметь сериализовать. Один вариант — ограничить T протоколом Codable и хранить JSON по безопасному имени файла.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
// Записывает data в файл с именем file.
func writeData(_ data: Data, to file: String) {
let documentDirectoryURL = FileManager.default.urls(for:
.documentDirectory, in: .userDomainMask).first!
let fileURL = documentDirectoryURL.appendingPathComponent(file)
try? data.write(to: fileURL)
}
// Удаляет файл с именем file.
func remove(file: String) {
let documentDirectoryURL = FileManager.default.urls(for:
.documentDirectory, in: .userDomainMask).first!
let fileURL = documentDirectoryURL.appendingPathComponent(file)
try? FileManager.default.removeItem(at: fileURL)
}
// Читает Data из файла с именем file. Если файл не существует, возвращает nil.
func readData(from file: String) -> Data? {
let documentDirectoryURL = FileManager.default.urls(for:
.documentDirectory, in: .userDomainMask).first!
let fileURL = documentDirectoryURL.appendingPathComponent(file)
return try? Data(contentsOf: fileURL)
}
final class DiskCache<T>: CacheProtocol { func setValue(_ value: T?, forKey key: String) {
}
func getValue(forKey key: String) -> T? {
}
func fetchValue(forKey key: String, completion: @escaping (T?) -> Void) {
}
}
Ответ
Для дискового кеша произвольный T нужно уметь сериализовать. Один вариант — ограничить T протоколом Codable и хранить JSON по безопасному имени файла.
Если CacheProtocol требует показанные getValue/setValue/fetchValue, реализация поверх данных функций может быть такой:
import Foundation
import CryptoKit
final class DiskCache<T: Codable>: CacheProtocol {
private func filename(_ key: String) -> String {
let hash = SHA256.hash(data: Data(key.utf8))
return hash.map { String(format: "%02x", $0) }.joined()
}
func setValue(_ value: T?, forKey key: String) {
guard let value else { remove(file: filename(key)); return }
guard let data = try? JSONEncoder().encode(value) else { return }
writeData(data, to: filename(key))
}
func getValue(forKey key: String) -> T? {
guard let data = readData(from: filename(key)) else { return nil }
return try? JSONDecoder().decode(T.self, from: data)
}
func fetchValue(forKey key: String,
completion: @escaping (T?) -> Void) {
completion(getValue(forKey: key))
}
}
Это синхронный учебный вариант, без защиты конкурентного доступа. Полный протокол в условии отсутствует: если он требует value(forKey:), имя нужно согласовать. Для production нужны каталог кеша, атомарная запись и передача ошибок; исходные helpers скрывают ошибки через try?. Дисковые операции нельзя выполнять в UI-пути на главном потоке.