Memory cache
Use a typed enum key and an identifiable Sendable value. The identifiable overload uses the value's ID as its cache key.
Examples
Each example is a standalone Swift package. Run it from the repository after moving into its directory or passing its path to SwiftPM.
Use a typed enum key and an identifiable Sendable value. The identifiable overload uses the value's ID as its cache key.
import SwiftStash
private struct Article: Identifiable, Sendable {
let id: ArticleKey
let title: String
}
private enum ArticleKey: String, CacheKey {
case concurrency
case actors
}
@main private enum MemoryCacheExample {
static func main() async {
let storage = MemoryStorageEngine<ArticleKey, Article>()
let cache = await Cache(
policy: .lru(threshold: 10 * 60),
storagePolicy: storage
)
await cache.add(Article(id: .concurrency, title: "A tour of Swift concurrency"))
await cache.add(Article(id: .actors, title: "Protecting state with actors"))
if let article = await cache[.concurrency] {
print("Read: \(article.title)")
}
let remainingCount = await cache.evictUntil(maxNbItems: 1)
print("Entries after eviction: \(remainingCount)")
}
}
Make the named directory first. The JSON serializer stores a Codable profile, and the cache reads the profile through its string ID.
import Foundation
import SwiftStash
private struct Profile: Codable, Identifiable, Sendable {
let id: String
let displayName: String
}
@main private enum DiskCacheExample {
static func main() async throws {
let directoryName = "profile-example"
try createCacheDirectory(named: directoryName)
let storage = DiskStorageEngine(
directory: directoryName,
serializer: JsonDiskStorageSerializer<Profile>()
)
let cache = await Cache(
policy: .lru(threshold: 24 * 60 * 60),
storagePolicy: storage
)
let profile = Profile(id: "42", displayName: "Ada")
await cache.add(profile)
if let cachedProfile = await cache[profile.id] {
print("Loaded from disk-backed cache: \(cachedProfile.displayName)")
}
}
private static func createCacheDirectory(named name: String) throws {
let bundleIdentifier = Bundle.main.bundleIdentifier ?? "app-cache"
let rootDirectory = URL.cachesDirectory
.appendingPathComponent("\(bundleIdentifier)-cache")
let directory = rootDirectory.appendingPathComponent(name)
try FileManager.default.createDirectory(
at: directory,
withIntermediateDirectories: true
)
}
}
A serializer converts one stored type to Data and back. This example persists a temperature as an eight-byte value.
import Foundation
import SwiftStash
private struct Temperature: Equatable, Sendable {
let celsius: Double
}
private struct TemperatureSerializer: DiskStorageSerializer {
func serialize(_ value: Temperature) throws -> Data {
withUnsafeBytes(of: value.celsius.bitPattern.bigEndian) { Data($0) }
}
func deserialize(_ data: Data) throws -> Temperature? {
guard data.count == MemoryLayout<UInt64>.size else {
return nil
}
var bits: UInt64 = 0
_ = withUnsafeMutableBytes(of: &bits) { data.copyBytes(to: $0) }
return Temperature(celsius: Double(bitPattern: UInt64(bigEndian: bits)))
}
}
@main private enum CustomSerializerExample {
static func main() async throws {
let directoryName = "temperature-example"
try createCacheDirectory(named: directoryName)
let storage = DiskStorageEngine(
directory: directoryName,
serializer: TemperatureSerializer()
)
let cache = await Cache(storagePolicy: storage)
await cache.add(Temperature(celsius: 21.5), for: "office")
if let temperature = await cache["office"] {
print("Office: \(temperature.celsius) °C")
}
}
private static func createCacheDirectory(named name: String) throws {
let bundleIdentifier = Bundle.main.bundleIdentifier ?? "app-cache"
let rootDirectory = URL.cachesDirectory
.appendingPathComponent("\(bundleIdentifier)-cache")
let directory = rootDirectory.appendingPathComponent(name)
try FileManager.default.createDirectory(
at: directory,
withIntermediateDirectories: true
)
}
}