it-swarm.com.de

Optional (""), wenn versucht wird, einen Wert von KeyChain zu erhalten

Wenn ich versuche, meinen keyChain-Wert abzurufen, wird eine Zeichenfolge zurückgegeben, die Folgendes enthält: 

Optional("[thing in the KeyChain]")

also habe ich versucht, "Optional" mit einer Schleife zu entfernen:

var str = KeychainService.loadToken()

for(var i = 0; i < 9 ; i++)
{
    str[i] = ""
}

Ich erhalte jedoch eine Fehlermeldung: NSString hat kein Mitglied mit dem Namen 'subscript'.

Die KeychainService-Klasse:

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
    }
}

Ich möchte nur das optionale Ding um den str Entfernen. Oder gibt es einen besseren Weg, das zu tun?

Ich habe diesen Code von:

http://matthewpalmer.net/blog/2014/06/21/example-ios-keychain-Swift-save-query/

14

Sie erhalten die Optional(""), da der optionale Wert nicht ausgepackt ist. Sie müssen einen ! hinter dem Objekt einfügen und erhalten nicht mehr das Optional("")-Bit. Ich würde Ihnen den Code zeigen, aber Sie haben uns die Anweisung print() nicht gezeigt. Ich habe unten einige Beispiele angefertigt, von denen ich denke, dass sie das Problem wiederholen würden, obwohl ich sie nicht ausprobiert habe.

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"

Ich hoffe, dies beantwortet Ihre Frage oder weist Sie zumindest in die richtige Richtung. Fragen Sie einfach, ob Sie weitere Informationen oder ein besseres Beispiel benötigen.

27
Jack Chorley

Hier ist eine Swift 2-Beispielimplementierung:

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)'")
}

Ausgabe:

benutzername: 'TestUser'
userValue: 'TestValue'
Schlüsselbundabfrage [acct: TestUser, v_Data: <54657374 56616c75 65>, svce: Service, Klasse: genp]
Wiederhergestellter Wert: 'TestValue' 

2
zaph

Sie können den Swift-Wrapper über die Keychain C-API verwenden und die oben genannten Probleme vollständig vermeiden. https://github.com/deniskr/KeychainSwiftAPI

1
Denis Krivitski

Sie erhalten die Option (""), da der optionale Wert nicht entpackt ist. Wenn Sie den optionalen Wert auspacken möchten, um den Zeichenfolgenwert zu erhalten, tun Sie dies 

yourValue.unsafelyUnwrapped

0
Ranjith