import Foundation import Security enum KeychainStore { static func loadString(service: String, account: String) -> String? { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: account, kSecReturnData as String: true, kSecMatchLimit as String: kSecMatchLimitOne, ] var item: CFTypeRef? let status = SecItemCopyMatching(query as CFDictionary, &item) guard status == errSecSuccess, let data = item as? Data else { return nil } return String(data: data, encoding: .utf8) } static func saveString(_ value: String, service: String, account: String) -> Bool { let data = Data(value.utf8) let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: account, ] let update: [String: Any] = [kSecValueData as String: data] let status = SecItemUpdate(query as CFDictionary, update as CFDictionary) if status == errSecSuccess { return true } if status != errSecItemNotFound { return false } var insert = query insert[kSecValueData as String] = data insert[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly return SecItemAdd(insert as CFDictionary, nil) == errSecSuccess } static func delete(service: String, account: String) -> Bool { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: account, ] let status = SecItemDelete(query as CFDictionary) return status == errSecSuccess || status == errSecItemNotFound } }