2011-11-08 44 views
10

我剛剛發現我的應用程序有一個有趣的問題。在應用程序中,我將用戶的用戶名和密碼保存到鑰匙串中。iOS KeychainItemWrapper未更新

keychainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyLoginPassword" accessGroup:nil]; 

[keychainWrapper setObject:usernameField.text forKey:(id)kSecAttrAccount]; 
[keychainWrapper setObject:passwordField.text forKey:(id)kSecValueData]; 

當這段代碼在Debug中運行時,它似乎工作得很好。它每次更新,我可以稍後從鑰匙串中檢索項目。當它在Distribution中運行時,鑰匙串永遠不會被更新。我已經驗證過,這兩行代碼在這兩個版本中都有效。我使用Xcode 4.2和iOS5 SDK,並在安裝了iOS5的iPad 2上運行應用程序。

回答

16

我也有這個問題,我花了永遠找出

有一個版本「KeychainWrapper」的左右浮動已是SecItemUpdate的NSAssert內(除其他事項外)。

無論誰做這個事情都是一個蠢事,當爲發佈/發佈構建時,每個NSAssert都是無效的,這意味着代碼甚至無法運行。

例如:

NSAssert(SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck), @"Couldn't update the Keychain Item."); 

需求,成爲實際SecItemUpdate是

OSStatus status = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck); 
NSAssert(status == noErr, @"Couldn't update the Keychain Item."); 

注意如何移動NSAssert外面,而不是結果檢查

重要提示: 嘗試更新kSecValueData的值,而不指定kSecAttrAccount的值,也會導致斷言失敗。所以,如果你的目的是存儲敏感數據(如信用卡號碼的列表)的一個字符串,一定要保存一些「帳戶名」文本在kSecAttrAccount屬性,就像這樣:

static NSString* kCardListXML = @"cardListXML"; 
static NSString* cardListAccountName = @"cardListAccount"; 

-(void)setCardListXML:(NSString*)xml { 
    KeychainItemWrapper* wrapper = 
    [[KeychainItemWrapper alloc] initWithIdentifier:kCardListXML accessGroup:nil]; 
    [wrapper setObject:cardListAccountName forKey:(id)CFBridgingRelease(kSecAttrAccount)]; 
    [wrapper setObject:xml forKey:(id)CFBridgingRelease(kSecValueData)]; 
}  

-(NSString*)getCardListXML { 
    KeychainItemWrapper* wrapper = 
    [[KeychainItemWrapper alloc] initWithIdentifier:kCardListXML accessGroup:nil]; 
    [wrapper setObject:cardListAccountName forKey:(id)CFBridgingRelease(kSecAttrAccount)]; 
    return [wrapper objectForKey:CFBridgingRelease(kSecValueData)]; 
} 
+0

我已經想通了,這本質上是問題所在。謝謝。 – iHorse

+0

KeychainWrapper的v1.2中似乎已經修復,可以從Xcode獲取示例代碼 – Olaf

14

如果包括

keychainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyLoginPassword" accessGroup:nil]; 

[keychainWrapper setObject:usernameField.text forKey:(id)kSecAttrAccount]; 
[keychainWrapper setObject:passwordField.text forKey:(id)kSecValueData]; 

你還必須包括

[keychainWrapper setObject:@"Myappstring" forKey: (id)kSecAttrService]; 

或者我得到一個 「SIGABRT」 的錯誤。 (Myappstring)是一個定義你的應用程序的字符串。

也許我錯過了一些東西,至少應該這樣做。

+0

KeychainItemWrapper大多爲我工作,處理了許多電子郵件地址(作爲用戶名存儲在kSecAttrAccount中),但是特別是一封電子郵件無法工作。然後,我爲kSecAttrService添加了上述行,現在全部完美! - 謝謝你@Andres – dbDev

+0

我一直在努力。很高興幫助 –

+1

此修復程序適用於我。從錯誤消息中弄清楚發生了什麼是非常棘手的,因爲如果您以前曾經正確設置這些值,您將看不到錯誤。只有當您更改initWithIdentifier:值並且未能設置kSecAttrService時,纔會發生錯誤。 – carbocation