2014-10-18 62 views
0

我在我的iOS應用程序的設備上保存userId作爲代幣與keychain。這適用於iPhone 5s/6/6 Plus,但不適用於iPhone 4s/5和iPad。在陳述我的應用程序時,我檢查鑰匙串中是否存在userId,或者是否存在func tokenExists()。但後來我得到一個錯誤:鑰匙扣類別不適用於iPhone 4s/5和iPad

fatal error: unexpectedly found nil while unwrapping an Optional value 

如下所示:

error message

這裏是我的鑰匙串類來保存,加載和刪除標記,並檢查令牌是否存在:

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

有沒有我的問題的解決方案?

回答

0

您的問題是您的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 
} 
+0

thx。這是解決方案! :)))) – Martin 2014-10-22 08:02:02

+0

如果這是解決方案,然後檢查綠色標記。很高興它對你有效。 – 2014-10-22 16:04:44

1

由於更新包含在了XCode 6.1,我現在要的地位比較errSecItemNotFound

var dataTypeRef: Unmanaged<AnyObject>? 
let status: OSStatus = SecItemCopyMatching(keychainQuery as CFDictionaryRef, &dataTypeRef) 
if (status != errSecItemNotFound) { 
    if let dataType = dataTypeRef? { 
     ... 
    } 
} 

直到此更新,我也做if let op = opaque? {,它正確地捕捉它是nil,但後來我開始嘗試解開零值的錯誤。

希望這有助於任何人在同一個問題上絆倒這個答案。