Type-safe key-value, file, and Keychain storage for iOS.
ForgeStorage covers every persistence need in a typical iOS app through three focused libraries. Each library exposes a protocol, a production implementation, and an in-memory test double — so you can swap the storage layer out for tests without touching your production code.
| Library | Protocol | Production | Test double | Use for |
|---|---|---|---|---|
| ForgeKVStore | KVStoring |
UserDefaultsKVStore, DiskKVStore |
InMemoryKVStore |
Settings, flags, small data |
| ForgeFileStore | FileStoring |
DiskFileStore |
InMemoryFileStore |
Images, videos, documents, cache |
| ForgeCrypt | CryptStoring |
CryptStore (Keychain) |
InMemoryCrypt |
Tokens, passwords, secrets |
| ForgeStorage | umbrella | — | — | Re-exports all three |
- Type-safe keys —
KVKey<T>andCryptKey<T>give compile-time safety for reads and writes - Protocol-oriented — every store is behind a protocol, making mocking trivial
- Reactive KV — wrap any
KVStoringwithKVReactiveStoreforAsyncStream-based observation - Configurable Keychain accessibility —
.whenUnlocked,.afterFirstUnlock,.whenUnlockedThisDeviceOnly, etc. - JSON convenience — built-in Codable round-trips for file and KV stores
- Zero Combine dependency — pure Swift Concurrency
- iOS 18+
- macOS 15+
- Swift 6.3+ (Xcode 26 or later)
- File → Add Package Dependencies…
- Paste
https://github.com/stefanprojchev/ForgeStorage.git - Set rule to Up to Next Major from
1.0.0
dependencies: [
.package(url: "https://github.com/stefanprojchev/ForgeStorage.git", from: "1.0.0")
],
targets: [
.target(
name: "YourApp",
dependencies: [
"ForgeStorage", // all three libraries
// — or pick individually —
// "ForgeKVStore",
// "ForgeFileStore",
// "ForgeCrypt",
]
)
]import ForgeKVStore
// Define typed keys
enum AppKeys {
static let onboarded = KVKey<Bool>("app.onboarded")
static let launchCount = KVKey<Int>("app.launchCount")
}
let store: KVStoring = UserDefaultsKVStore()
try store.set(AppKeys.onboarded, value: true)
let done = store.get(AppKeys.onboarded) ?? falseimport ForgeKVStore
let reactive = KVReactiveStore(UserDefaultsKVStore())
for await value in reactive.stream(AppKeys.launchCount) {
print("Launch count:", value ?? 0)
}import ForgeFileStore
let store = DiskFileStore(directory: .caches, namespace: "avatars")
try await store.save(imageData, to: "user_42.jpg")
let data = try await store.load("user_42.jpg")
// JSON convenience
try await store.saveJSON(user, to: "user.json")
let loaded: User = try await store.loadJSON("user.json")import ForgeCrypt
enum AuthKeys {
static let accessToken = CryptKey<String>(
key: "auth.accessToken",
accessibility: .afterFirstUnlock
)
}
let keychain: CryptStoring = CryptStore(service: "com.yourapp")
try keychain.set("eyJhbG...", for: AuthKeys.accessToken)
let token: String? = try keychain.get(AuthKeys.accessToken)
try keychain.delete(AuthKeys.accessToken)Every store has an in-memory test double you can use instead of the production implementation:
import Testing
import ForgeKVStore
@Test
func incrementsLaunchCount() throws {
let store: KVStoring = InMemoryKVStore()
let initial = store.get(AppKeys.launchCount) ?? 0
try store.set(AppKeys.launchCount, value: initial + 1)
#expect(store.get(AppKeys.launchCount) == 1)
}ForgeStorage is part of the Forge family of Swift packages for iOS.
| Package | Description |
|---|---|
| ForgeCore | Thread-safe primitives for iOS Swift packages. |
| ForgeInject | Dependency injection with constructor and property wrapper support. |
| ForgeObservers | Reactive system observers — connectivity, lifecycle, keyboard, and more. |
| ForgeStorage | Type-safe key-value, file, and Keychain storage. |
| ForgeDB | Type-safe repository pattern and GRDB-backed SQLite persistence. |
| ForgeOrchestrator | Orchestrate app flows — startup gates, data pipelines, and continuous monitors. |
| ForgePush | Push notification management — permissions, tokens, and routing. |
| ForgeLocation | Location triggers — geofencing, significant changes, and visits. |
| ForgeBackgroundTasks | Background task scheduling and dispatch. |
| ForgeNetworking | Typed, async/await-first HTTP networking with auth, retry, and background transfers. |
| ForgeLog | Structured logging with pluggable providers and a built-in inspector UI. |
| ForgeAccess | Subscription-aware feature gating with override channels and debug UI. |
ForgeStorage is released under the MIT License. See LICENSE.