Beginner-friendly Keychain library for Apple platforms.
import SwiftKey
let key = SwiftKey.Beginner()
key.setString("username", "Ricky")
let username = key.getString("username", default: "Guest")
print(username)
if let error = key.lastErrorMessage {
print("SwiftKey error:", error)
}This path is non-throwing and easiest for beginners.
- Open
File > Add Packages... - Use:
https://github.com/ricky-stone/SwiftKey.git - Select
Up to Next Majorfrom1.1.0
dependencies: [
.package(url: "https://github.com/ricky-stone/SwiftKey.git", from: "1.1.0")
]SwiftKey.Beginner: notry/catch, returns defaults and trackslastErrorMessage.SwiftKey:throwsAPI for full control.SwiftKeyStore+Resulthelpers: good for app service layers.asyncwrappers: same behavior in async contexts.
import SwiftKey
let key = SwiftKey.Beginner()
key.setString("token", "abc123")
key.setInt("launchCount", 1)
key.setBool("isPro", true)
key.setDouble("taxRate", 0.2)
let token = key.getString("token", default: "")
let launchCount = key.getInt("launchCount", default: 0)
let isPro = key.getBool("isPro", default: false)
let taxRate = key.getDouble("taxRate", default: 0)struct User: Codable {
let name: String
let age: Int
}
let key = SwiftKey.Beginner()
let user = User(name: "Ricky", age: 29)
key.setModel("user", user)
let storedUser = key.getModel("user", as: User.self)let key = SwiftKey.Beginner()
_ = key.setString(" ", "bad")
if let message = key.lastErrorMessage {
print("Last error:", message)
}import SwiftKey
let key = SwiftKey()
try key.addKey("username", "Ricky")
let username = try key.getKey("username", as: String.self)
try key.updateKey("username", "Ricky Stone")
let removed = try key.removeKey("username")
print("Removed:", removed)These are available if you prefer simpler names.
try key.set("username", "Ricky")
let value: String? = try key.get("username")
let exists = try key.contains("username")
let removed = try key.remove("username")
try key.clear()let userKey = SwiftKey.Key<User>("profile.user")
try key.set(userKey, User(name: "Ricky", age: 29))
let user = try key.get(userKey)Typed keys reduce string typo mistakes in app code.
Use namespaces to group keys.
let auth = key.namespace("auth")
try auth.set("token", "abc123")
let token = try auth.get("token", as: String.self)
let keys = try auth.keys() // ["token"]You can also build namespaced typed keys.
let namespacedUserKey = auth.key("user", as: User.self)
try key.set(namespacedUserKey, User(name: "Ricky", age: 29))let key = SwiftKey(
service: "com.example.myapp",
accessGroup: nil,
synchronizable: true,
accessibility: .afterFirstUnlock
)When synchronizable is true:
- SwiftKey tries iCloud-synced Keychain first.
- If sync fails due availability/entitlement issues, SwiftKey falls back to local non-sync storage.
Helpers:
let syncRequested = key.isSynchronizableRequested
let syncAvailable = key.canUseSynchronizableStorage()let report = key.diagnose()
print(report.notes.joined(separator: "\n"))let key = SwiftKey(debugLogHandler: { entry in
print("[\(entry.level.rawValue)] \(entry.operation): \(entry.message)")
})let result = key.setResult("token", "abc123")
switch result {
case .success:
print("saved")
case .failure(let error):
print(error.localizedDescription)
}Also available:
getResultremoveResultclearResultkeysResult
try await key.setAsync("token", "abc123")
let token: String? = try await key.getAsync("token", as: String.self)
let removed = try await key.removeAsync("token")try key.addKey("token", "abc123")
try key.migrateKey(from: "token", to: "auth.token")
try key.addKey("user.old", User(name: "Ricky", age: 29))
try key.migrateModel(from: "user.old", to: "user.current", as: User.self)InMemorySwiftKeyStore is useful for deterministic tests without touching device keychain.
let store: SwiftKeyStore = InMemorySwiftKeyStore()
try store.set("username", "Ricky")
let username = try store.get("username", as: String.self)invalidKey: key is empty or whitespace.duplicateKey: target key exists when overwrite is not allowed.keyNotFound: requested key does not exist.encodingFailed:Codablevalue could not encode.decodingFailed: stored data does not match requested type.unhandledStatus(code): underlying Keychain status from Security framework.
swift testMIT License
Copyright (c) 2026 Ricky Stone