Classes

The following classes are available globally.

  • KeychainStorage is a generic class that conforms to the StorageDelegate protocol, providing a secure storage solution by leveraging the keychain. It is designed to store, retrieve, and manage objects of type T, where T must conform to the Codable protocol. This requirement ensures that the objects can be easily encoded and decoded for secure storage in the keychain.

    See more

    Declaration

    Swift

    public class KeychainStorage<T> : StorageDelegate<T>, @unchecked Sendable where T : Decodable, T : Encodable, T : Sendable

    Parameters

    T

    The type of the objects to be stored in the keychain. Must conform to Codable.

  • MemoryStorage provides an in-memory storage solution with optional caching strategies.

    This class combines the simplicity of in-memory storage with the flexibility of caching strategies. It’s built on top of StorageDelegate and uses the Memory<T> actor for the underlying storage.

    Overview

    MemoryStorage is ideal for temporary data that doesn’t need to persist across app launches. Since the underlying storage is already in memory, the caching layer adds an additional level of indirection that can be useful for specific scenarios.

    When to Use Memory Storage

    • Temporary session data: User session information that’s cleared on logout
    • In-flight data: Data being processed that doesn’t need persistence
    • Performance testing: Testing storage patterns without disk I/O overhead
    • Cached computations: Results that can be recomputed if needed

    Caching with Memory Storage

    While it may seem redundant to cache in-memory storage, the caching layer can be useful for:

    Testing Cache Behavior

    // Test how your app handles cache strategies
    let storage = MemoryStorage<Config>(cacheStrategy: .CACHE_ON_FAILURE)
    // Simulate failures and verify fallback behavior
    

    Consistent API

    // Use the same caching API across all storage types
    let memStorage = MemoryStorage<Token>(cacheStrategy: .CACHE)
    let keychainStorage = KeychainStorage<Token>(cacheStrategy: .CACHE)
    // Both support the same operations and strategies
    

    Performance Benchmarking

    let noCacheStorage = MemoryStorage<Data>(cacheStrategy: .NO_CACHE)
    let cachedStorage = MemoryStorage<Data>(cacheStrategy: .CACHE)
    // Compare performance characteristics
    

    Typical Usage

    For most use cases with MemoryStorage, use .NO_CACHE (the default) since the underlying storage is already in memory:

    // Default: no additional cache layer (recommended)
    let sessionData = MemoryStorage<Session>()
    try await sessionData.save(item: currentSession)
    

    Migration from Legacy API

    The cacheable parameter is removed. Use cacheStrategy instead:

    Before:

    let storage = MemoryStorage<User>(cacheable: true)
    

    After:

    let storage = MemoryStorage<User>(cacheStrategy: .CACHE)
    

    Thread Safety

    All operations are thread-safe through Swift actor isolation. Concurrent access from multiple tasks is handled safely without external synchronization.

    Important

    Data stored in MemoryStorage is lost when the app terminates. Use KeychainStorage or other persistent storage for data that must survive app restarts.

    See more

    Declaration

    Swift

    public class MemoryStorage<T> : StorageDelegate<T>, @unchecked Sendable where T : Decodable, T : Encodable, T : Sendable

    Parameters

    T

    The type of the objects to be stored. Must conform to Codable for serialization and Sendable for safe concurrent access.

  • A storage delegate class that provides flexible caching strategies for storage operations.

    StorageDelegate acts as a wrapper around any Storage implementation, adding an optional in-memory caching layer. This enables various performance and resilience patterns depending on your application’s requirements.

    Overview

    The delegate pattern allows you to:

    • Add caching to any storage implementation without modifying the underlying storage
    • Choose from multiple caching strategies to match your use case
    • Maintain thread-safe concurrent access through Swift actors
    • Provide degraded functionality during storage failures

    Caching Strategies

    Three caching strategies are available through the CacheStrategy enum:

    NO_CACHE (Default)

    All operations go directly to the underlying storage with no caching layer.

    let storage = StorageDelegate(
        delegate: KeychainStorage(),
        cacheStrategy: .NO_CACHE
    )
    

    Use when: You always need fresh data and memory usage is a concern.

    CACHE

    Items are cached in memory on save. Reads are served from cache when available.

    let storage = StorageDelegate(
        delegate: RemoteStorage(),
        cacheStrategy: .CACHE
    )
    

    Use when: Performance is critical and you can tolerate cache-storage inconsistencies on failures.

    CACHE_ON_FAILURE

    Items are cached after successful operations. Cache serves as fallback during storage failures.

    let storage = StorageDelegate(
        delegate: NetworkStorage(),
        cacheStrategy: .CACHE_ON_FAILURE
    )
    

    Use when: You need resilience against intermittent failures and can tolerate stale data.

    Thread Safety

    All caching operations are thread-safe through the use of Swift actors. Multiple concurrent reads and writes are handled safely without the need for external synchronization.

    Example Usage

    // High-performance cached configuration
    let config = StorageDelegate(
        delegate: KeychainStorage(account: "app.config"),
        cacheStrategy: .CACHE
    )
    try await config.save(item: appConfig)
    let cachedConfig = try await config.get() // Served from cache
    
    // Resilient network storage
    let userData = StorageDelegate(
        delegate: NetworkKeychain(account: "user.data"),
        cacheStrategy: .CACHE_ON_FAILURE
    )
    try await userData.save(item: user)
    // Later, even if network fails...
    let user = try await userData.get() // Falls back to cache
    

    Note

    This class is designed to be subclassed by specific storage strategies (e.g., MemoryStorage, KeychainStorage) that conform to the Storage protocol.

    See more

    Declaration

    Swift

    open class StorageDelegate<T> : Storage, @unchecked Sendable where T : Decodable, T : Encodable, T : Sendable

    Parameters

    T

    The type of the object being stored. Must conform to Codable and Sendable to ensure safe encoding/decoding and concurrent access.