Summary: - Sources: Models - Added symbols: enum FileDirectory - Removed symbols: enum FileDirectory Stats: - 1 file changed, 1 insertion(+), 1 deletion(-) |
||
|---|---|---|
| Sources/LocalData | ||
| Tests/LocalDataTests | ||
| .gitignore | ||
| Package.resolved | ||
| Package.swift | ||
| Proposal.md | ||
| README.md | ||
LocalData
LocalData provides a typed, discoverable namespace for persisted app data across UserDefaults, Keychain, and file storage with optional encryption.
Architecture
The package uses a clean, modular architecture with isolated actors for thread safety:
StorageRouter (main entry point)
├── UserDefaultsHelper
├── KeychainHelper
├── FileStorageHelper
├── EncryptionHelper
└── SyncHelper
What Ships in the Package
Protocols
- StorageKey - Define storage configuration for each data type
- StorageProviding - Abstraction for storage operations
Services (Actors)
- StorageRouter - Main entry point for all storage operations
- KeychainHelper - Secure keychain storage
- EncryptionHelper - AES-256-GCM or ChaCha20-Poly1305 with PBKDF2/HKDF
- FileStorageHelper - File system operations
- UserDefaultsHelper - UserDefaults with suite support
- SyncHelper - WatchConnectivity sync
Models
- StorageDomain - userDefaults, keychain, fileSystem, encryptedFileSystem
- SecurityPolicy - none, keychain, encrypted (AES-256 or ChaCha20-Poly1305)
- Serializer - JSON, plist, Data, or custom
- PlatformAvailability - all, phoneOnly, watchOnly, phoneWithWatchSync
- SyncPolicy - never, manual, automaticSmall
- KeychainAccessibility - All 7 iOS accessibility options
- KeychainAccessControl - All 6 access control options (biometry, passcode, etc.)
- FileDirectory - documents, caches, custom URL
- StorageError - Comprehensive error types
- AnyCodable - Type-erased Codable for mixed-type payloads
Usage
1. Define Keys
Extend StorageKeys with your own key types:
import LocalData
extension StorageKeys {
struct UserTokenKey: StorageKey {
typealias Value = String
let name = "user_token"
let domain: StorageDomain = .keychain(service: "com.myapp")
let security: SecurityPolicy = .keychain(
accessibility: .afterFirstUnlock,
accessControl: .biometryAny
)
let serializer: Serializer<String> = .json
let owner = "AuthService"
let availability: PlatformAvailability = .phoneOnly
let syncPolicy: SyncPolicy = .never
}
}
If you omit security, it defaults to SecurityPolicy.recommended.
2. Use StorageRouter
// Save
let key = StorageKeys.UserTokenKey()
try await StorageRouter.shared.set("token123", for: key)
// Retrieve
let token = try await StorageRouter.shared.get(key)
// Remove
try await StorageRouter.shared.remove(key)
Storage Domains
| Domain | Use Case |
|---|---|
userDefaults |
Preferences, small settings |
keychain |
Credentials, tokens, sensitive data |
fileSystem |
Documents, cached data, large files |
encryptedFileSystem |
Sensitive files with encryption policies |
Security Options
Keychain Accessibility
whenUnlocked- Only when device unlockedafterFirstUnlock- After first unlock until restartwhenUnlockedThisDeviceOnly- No migration to new deviceafterFirstUnlockThisDeviceOnly- No migrationalways- Always accessible (least secure)alwaysThisDeviceOnly- Always, no migrationwhenPasscodeSetThisDeviceOnly- Requires passcode
Access Control
userPresence- Any authenticationbiometryAny- Face ID or Touch IDbiometryCurrentSet- Current enrolled biometric onlydevicePasscode- Passcode onlybiometryAnyOrDevicePasscode- Biometric preferred, passcode fallbackbiometryCurrentSetOrDevicePasscode- Current biometric or passcode
Encryption
- AES-256-GCM or ChaCha20-Poly1305
- PBKDF2-SHA256 or HKDF-SHA256 key derivation
- Configurable PBKDF2 iteration count
- Master key stored securely in keychain
- Default security policy:
SecurityPolicy.recommended(ChaCha20-Poly1305 + HKDF)
Sync Behavior
StorageRouter can sync data to Apple Watch via WCSession when:
availabilityis.allor.phoneWithWatchSyncsyncPolicyis.manualor.automaticSmall(≤100KB)- WCSession is activated and watch is paired
The app owns WCSession activation and handling incoming updates.
Platforms
- iOS 17+
- watchOS 10+
Testing
- Unit tests use Swift Testing (
Testingpackage)
Sample App
See SecureStorgageSample for working examples of all storage domains and security options.