我在iOS应用程序的设备上使用userIdkeychain作为令牌保存。此功能适用于iPhone 5s / 6/6 Plus,但不适用于iPhone 4s / 5和iPad。在陈述我的应用程序时,我使用userId检查钥匙串中是否存在func tokenExists()。但是然后我得到一个错误:

fatal error: unexpectedly found nil while unwrapping an Optional value


如此处所示:



这是我的钥匙串类,用于保存,加载和删除令牌并检查令牌是否存在:

import UIKit
import Security

// Identifiers
let userAccount:String = "userAccount"

class KeychainService: NSObject {

/*
save token to keychain
*/
func deleteToken() {
    self.delete("userId")
}

/*
save token to keychain
*/
func saveToken(token: NSString) {
    self.save("userId", data: token)
}

/*
load keychain token
*/
func loadToken() -> NSString? {
    var token: AnyObject? = self.load("userId")

    return token as? NSString
}

func tokenExists() -> Bool {

    let token:NSString = loadToken()!

    if (token == "") {
        return false
    }
    else {
        return true
    }
}

private func delete(service: NSString) {
    //var dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
    // Instantiate a new default keychain query
    var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPassword, service, userAccount], forKeys: [kSecClass, kSecAttrService, kSecAttrAccount])

    // Delete any existing items
    SecItemDelete(keychainQuery as CFDictionaryRef)

    // Check that it worked ok
    //println("Token deleted")
}

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

private 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()
    var contentsOfKeychain: NSString?

    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)
        contentsOfKeychain = NSString(data: retrievedData, encoding: NSUTF8StringEncoding)
        //println("The decoded string is \(str)")
    } else {
        //println("Nothing was retrieved from the keychain.")
    }

    return contentsOfKeychain
}
}


我的问题有解决方案吗?

最佳答案

您的问题是您的tokenExists()方法不检查令牌是否存在。相反,它假定tokenExists(如!末尾的let token:NSString = loadToken()!所示),然后仅检查它是否为空字符串。

尝试以下tokenExists()方法:

func tokenExists() -> Bool {
    var result = false
    if let token = loadToken() {
        // the token exists, but is it blank?
        if token != "" {
            // no, the token is not blank
            result = true
        }
    }
    return result
}

关于ios - 钥匙串(keychain)类不适用于iPhone 4s/5和iPad,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26438767/

10-09 10:09