Junior
What is the difference between Keychain and User Defaults?
sobes.tech AI
Answer from AI
UserDefaults is used for storing small, non-confidential data such as user settings or app state. Data is stored as key-value pairs in a .plist file and is accessible to all parts of the app. UserDefaults does not encrypt data and is not suitable for storing critical information.
Keychain is used for securely storing confidential data such as passwords, certificates, tokens, and other sensitive information. Data is encrypted and stored in a specialized storage accessible only to the app that saved it. Keychain is supported at the OS level and provides a high level of data protection.
Key differences:
| Characteristic | UserDefaults | Keychain |
|---|---|---|
| Purpose | Storage of non-confidential settings | Storage of confidential data (passwords, tokens) |
| Security | No built-in encryption | Data is encrypted |
| Access | Accessible to all parts of the app | Accessible only to the app that saved it |
| Data volume | Suitable for small amounts of data | Suitable for small amounts of confidential data |
| Implementation | Simple API, stored in a .plist file |
More complex API, stored in system storage |
Example of using UserDefaults:
// Saving a value
UserDefaults.standard.set("dark", forKey: "theme")
// Retrieving a value
let theme = UserDefaults.standard.string(forKey: "theme")
Example of using Keychain (requires working with SecItem API or wrappers):
// Example of adding a password (simplified, requires error handling and additional parameters)
let password = "mySecretPassword".data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "myAccount",
kSecValueData as String: password
]
let statusAdd = SecItemAdd(query as CFDictionary, nil)
// Handle status
// Example of retrieving a password (simplified, requires error handling)
let queryGet: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "myAccount",
kSecReturnData as String: kCFBooleanTrue!,
kSecMatchLimit as String: kSecMatchLimitOne
]
var item: CFTypeRef?
let statusGet = SecItemCopyMatching(queryGet as CFDictionary, &item)
if statusGet == errSecSuccess {
let retrievedData = item as! Data
let retrievedPassword = String(data: retrievedData, encoding: .utf8)
// Use the password
}