【发布时间】:2014-08-11 00:51:01
【问题描述】:
我无法将所有可用于从iOS Keychain 添加数据和查询数据的Objective C 代码示例转换为Swift。我正在尝试对字符串(访问令牌)进行基本存储并将其读回。我已经查看了有关 Stack Overflow 的其他一些问题,但我无法让它发挥作用。我试图从各种来源拼凑出一个解决方案。
编辑 1: 我尝试了更基本的设置,因为我认为我的 self.defaultKeychainQuery 可能把事情搞砸了。我已将以下代码更新为最新版本。
编辑 2: 搞定了。我没有正确地将数据值添加到保存查询中。我需要将字符串转换为 NSData。我已将以下代码更新为最新的工作版本。
编辑 3: 正如 Xerxes 在下面指出的那样,由于字典的某些问题,此代码不适用于高于 Beta 1 的 Xcode 版本。如果您知道解决此问题的方法,请告诉我。
更新:我把它变成了keychain library written in Swift called Locksmith。
保存
class func save(service: NSString, data: NSString) {
var dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
// Instantiate a new default keychain query
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPassword, service, userAccount, dataFromString], forKeys: [kSecClass, kSecAttrService, kSecAttrAccount, kSecValueData])
// Delete any existing items
SecItemDelete(keychainQuery as CFDictionaryRef)
// Add the new keychain item
var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)
// Check that it worked ok
println("Saving status code is: \(status)")
}
加载
class func load(service: NSString) -> AnyObject? {
// Instantiate a new default keychain query
// Tell the query to return a result
// Limit our results to one item
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPassword, service, userAccount, kCFBooleanTrue, kSecMatchLimitOne], forKeys: [kSecClass, kSecAttrService, kSecAttrAccount, kSecReturnData, kSecMatchLimit])
// I'm not too sure what's happening here...
var dataTypeRef :Unmanaged<AnyObject>?
// Search for the keychain items
let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
println("Loading status code is: \(status)")
// I'm not too sure what's happening here...
let opaque = dataTypeRef?.toOpaque()
if let op = opaque? {
let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
println("Retrieved the following data from the keychain: \(retrievedData)")
var str = NSString(data: retrievedData, encoding: NSUTF8StringEncoding)
println("The decoded string is \(str)")
} else {
println("Nothing was retrieved from the keychain.")
}
return nil
}
用法(视图控制器)
KeychainService.saveToken("sometoken")
KeychainService.loadToken()
使用这些便捷方法
class func saveToken(token: NSString) {
self.save("service", data: token)
}
class func loadToken() {
var token = self.load("service")
if let t = token {
println("The token is: \(t)")
}
}
这导致控制台中的输出:
Saving status code is: 0
Loading status code is: 0
Retrieved the following data from the keychain: <736f6d65 746f6b65 6e>
The decoded string is sometoken
非常感谢您的帮助。我不太确定一旦获得 dataTypeRef 后如何处理它,或者它是否有上面代码给出的任何数据。
【问题讨论】:
-
我仍在等待完成这项工作,但没有比这更明智的了。事实上,在最新版本的 Xcode 中,使用“NSDictionary”时我会收到一条错误消息。真的不应该这么沮丧!祝你好运......我会密切关注。
-
@Darren 我想我已经成功了。查看上面的编辑版本。我没有将 NSString 输入转换为正确的 NSData,也没有将实际数据值添加到 keychainQuery。更改此设置后,我不得不更改
load方法来解码 NSData 响应。让我知道这是否对您有帮助:) -
您使用的是哪个版本的 Xcode?我已经在 Beta-2 中尝试过您的代码,并且从
keychainQuery的定义中不断收到以下错误消息Could not find an overload for 'init' that accepts the supplied arguments。自从我改用 beta-2 后,这才开始发生在我身上。感谢您的回复。 -
我想我可能是第一个测试版(版本 6.0 (6A215l))。您是否尝试过使用任何其他可用方法设置键/值对?可能只是
NSMutableDictionary(objects:keys:),特别是那是错误的。 -
matt - 你打算用这个新图书馆制作一个 Cocoapod 吗?我很想尝试一下,我真的不想用子模块导入它:)
标签: ios swift local-storage keychain