У меня возникли проблемы с преобразованием всех образцов кода Objective C
, которые доступны для добавления данных и запроса данных из iOS Keychain
в Swift. Я пытаюсь сделать базовое хранение строки (токен доступа) и прочитать ее обратно. Я просмотрел некоторые другие вопросы о переполнении стека, но я не могу заставить его работать. Я попытался объединить решение из разных источников.
Изменить 1: Я попытался с более базовой настройкой, потому что думал, что мой self.defaultKeychainQuery, возможно, запутался. Я обновил код ниже до последней версии.
Изменить 2:. Он работает. Я не добавлял значение данных в запрос сохранения правильно. Мне нужно было преобразовать строку в NSData. Я обновил код до последней рабочей версии.
Изменить 3: Как указывает Xerxes ниже, этот код не работает с версиями Xcode выше Beta 1 из-за некоторой проблемы со словарями. Если вы знаете об этом, сообщите мне.
Обновление: я превратил это в библиотеку ключей, написанную в Swift, называемую 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)")
}
Load
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 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 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, как только у меня получится, или если у него есть данные, приведенные выше.