Lorsque j'essaie d'obtenir ma valeur keyChain, elle renvoie une chaîne contenant:
Optional("[thing in the KeyChain]")
alors, j'ai essayé de supprimer "facultatif" en utilisant une boucle:
var str = KeychainService.loadToken()
for(var i = 0; i < 9 ; i++)
{
str[i] = ""
}
Mais je reçois une erreur: NSString n'a pas de membre nommé 'indice'
La classe KeychainService:
import Foundation
import Security
let serviceIdentifier = "MySerivice"
let userAccount = "authenticatedUser"
let accessGroup = "MySerivice"
// Arguments for the keychain queries
let kSecClassValue = kSecClass.takeRetainedValue() as NSString
let kSecAttrAccountValue = kSecAttrAccount.takeRetainedValue() as NSString
let kSecValueDataValue = kSecValueData.takeRetainedValue() as NSString
let kSecClassGenericPasswordValue = kSecClassGenericPassword.takeRetainedValue() as NSString
let kSecAttrServiceValue = kSecAttrService.takeRetainedValue() as NSString
let kSecMatchLimitValue = kSecMatchLimit.takeRetainedValue() as NSString
let kSecReturnDataValue = kSecReturnData.takeRetainedValue() as NSString
let kSecMatchLimitOneValue = kSecMatchLimitOne.takeRetainedValue() as NSString
class KeychainService: NSObject {
/**
* Exposed methods to perform queries.
* Note: feel free to play around with the arguments
* for these if you want to be able to customise the
* service identifier, user accounts, access groups, etc.
*/
internal class func saveToken(token: NSString) {
self.save(serviceIdentifier, data: token)
}
internal class func loadToken() -> NSString? {
var token = self.load(serviceIdentifier)
return token
}
/**
* Internal methods for querying the keychain.
*/
private 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: [kSecClassGenericPasswordValue, service, userAccount, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue])
// Delete any existing items
SecItemDelete(keychainQuery as CFDictionaryRef)
// Add the new keychain item
var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)
}
private class func load(service: NSString) -> String? {
// Instantiate a new default keychain query
// Tell the query to return a result
// Limit our results to one item
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])
var dataTypeRef :Unmanaged<AnyObject>?
// Search for the keychain items
let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
let opaque = dataTypeRef?.toOpaque()
var contentsOfKeychain: String?
if let op = opaque? {
let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
// Convert the data retrieved from the keychain into a string
contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding)
} else {
println("Nothing was retrieved from the keychain. Status code \(status)")
}
return contentsOfKeychain
}
}
Je ne veux tout simplement pas supprimer l'option en option autour de la chaîne .__ Ou y a-t-il une meilleure façon de le faire?
J'ai pris ce code de:
http://matthewpalmer.net/blog/2014/06/21/example-ios-keychain-Swift-save-query/
Vous obtenez la Optional("")
car la valeur facultative n'est pas décompressée. Vous devez mettre un !
après l'objet et vous n'obtiendrez plus le bit Optional("")
. Je voudrais vous montrer le code mais vous ne nous avez pas montré la déclaration print()
. J'ai créé quelques exemples ci-dessous qui, je pense, reproduiraient le problème, bien que je ne les aie pas essayés.
var value:String?
value = "Hello, World"
print("The Value Is \(value)") // Prints "The Value Is Optional(Hello, World)"
print("The Value Is \(value!)")// Prints "The Value Is Hello, World"
J'espère que cela répond à votre question ou du moins vous oriente dans la bonne direction. Demandez juste si vous avez besoin de plus d'informations ou d'un meilleur exemple.
Voici un exemple d'implémentation de Swift 2:
import Security
class ZLKeychainService: NSObject {
var service = "Service"
var keychainQuery :[NSString: AnyObject]! = nil
func save(name name: NSString, value: NSString) -> OSStatus? {
let statusAdd :OSStatus?
guard let dataFromString: NSData = value.dataUsingEncoding(NSUTF8StringEncoding) else {
return nil
}
keychainQuery = [
kSecClass : kSecClassGenericPassword,
kSecAttrService : service,
kSecAttrAccount : name,
kSecValueData : dataFromString]
if keychainQuery == nil {
return nil
}
SecItemDelete(keychainQuery as CFDictionaryRef)
statusAdd = SecItemAdd(keychainQuery! as CFDictionaryRef, nil)
return statusAdd;
}
func load(name name: NSString) -> String? {
var contentsOfKeychain :String?
keychainQuery = [
kSecClass : kSecClassGenericPassword,
kSecAttrService : service,
kSecAttrAccount : name,
kSecReturnData : kCFBooleanTrue,
kSecMatchLimit : kSecMatchLimitOne]
if keychainQuery == nil {
return nil
}
var dataTypeRef: AnyObject?
let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
if (status == errSecSuccess) {
let retrievedData: NSData? = dataTypeRef as? NSData
if let result = NSString(data: retrievedData!, encoding: NSUTF8StringEncoding) {
contentsOfKeychain = result as String
}
}
else {
print("Nothing was retrieved from the keychain. Status code \(status)")
}
return contentsOfKeychain
}
}
//Test:
let userName = "TestUser"
let userValue: NSString = "TestValue"
print("userName: '\(userName)'")
print("userValue: '\(userValue)'")
let kcs = ZLKeychainService()
kcs.save(name:userName, value: userValue)
print("Keychain Query \(kcs.keychainQuery)")
if let recoveredToken = kcs.load(name:userName) {
print("Recovered Value: '\(recoveredToken)'")
}
Sortie:
userName: 'TestUser'
userValue: 'TestValue'
Requête de trousseau [acct: TestUser, v_Data: <54657374 56616c75 65>, svce: Service, classe: genp]
Valeur récupérée: 'TestValue'
Vous pouvez utiliser l'encapsuleur Swift sur l'API Keychain C et éviter les problèmes ci-dessus. https://github.com/deniskr/KeychainSwiftAPI
Vous obtiendrez facultatif ("") car la valeur facultative n'est pas décompressée et si vous souhaitez décompresser la valeur facultative pour obtenir la valeur de chaîne,
yourValue.unsafelyUnwrapped