你好,我遇到了一个非常奇怪的问题,iOS密钥链在更新存储在密钥链中的登录信息.因此,如果没有保存的凭据,则运行保存功能会正确地保存日志(log)信息.如果登录信息已经存在,并且用户更新了他们的密码,则更新功能将正确地仅更新密码.但如果登录信息存在,并且我try 更改邮箱(同时保留或更改密码),则第一次更新不会成功.我必须手动点击两次更新登录信息才能更新登录信息.我try 了下面的代码,只是强制DELETE和SAVE函数运行两次,同时在两次之间添加一个延迟,但这不起作用.唯一有效的方法是按两次"更新"键.我很感激你们的帮助.谢谢.
delete(email: result.0)
save(email: email, password: password)
Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { _ in
delete(email: result.0)
save(email: email, password: password)
}
func save(email: String, password: String) {
let passwordData = password.data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "https://hustle.page",
kSecAttrAccount as String: email,
kSecValueData as String: passwordData
]
let saveStatus = SecItemAdd(query as CFDictionary, nil)
if saveStatus == errSecDuplicateItem {
update(email: email, password: password)
}
}
func update(email: String, password: String) {
if let result = read(service: "https://hustle.page"){
if result.0 == email {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "https://hustle.page",
kSecAttrAccount as String: email
]
let passwordData = password.data(using: .utf8)!
let updatedData: [String: Any] = [
kSecValueData as String: passwordData
]
SecItemUpdate(query as CFDictionary, updatedData as CFDictionary)
} else {
delete(email: result.0)
save(email: email, password: password)
Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { _ in
delete(email: result.0)
save(email: email, password: password)
}
}
}
}
func delete(email: String) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "https://hustle.page",
kSecAttrAccount as String: email
]
SecItemDelete(query as CFDictionary)
}
func read(service: String) -> (String, String)? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecReturnAttributes as String: true,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
if status == errSecSuccess, let item = result as? [String: Any] {
if let account = item[kSecAttrAccount as String] as? String,
let passwordData = item[kSecValueData as String] as? Data,
let password = String(data: passwordData, encoding: .utf8) {
return (account, password)
}
}
return nil
}
in the view:
Button {
save(email: email, password: password)
} label: {
Text("Update")
}