2010-08-29 64 views
5

我用下面的代碼來檢索從iPhone鑰匙串的登錄憑據:問題使用KeychainItemWrapper

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Test" accessGroup:nil]; 
NSString *username = [wrapper objectForKey:(id)kSecAttrAccount]; 
NSString *password = [wrapper objectForKey:(id)kSecValueData]; 
[wrapper release]; 

我的第一次用戶啓動應用程序的印象,無論是用戶名密碼也可能是從鑰匙鏈中檢索,所以usernamepassword應該等於nil。但是,我無法使用NSLog打印出任何這些變量。

有什麼建議嗎?

+0

什麼是你能打印嗎?爲什麼不在運行時設置斷點並檢查對象? – vfn 2010-08-30 01:17:35

+0

什麼都沒有。當我嘗試打印對象時沒有任何顯示。檢查它們只會以0xSOMETHING的形式顯示地址。 – 2010-08-30 11:15:24

+0

@Anh愚蠢的問題,但你有沒有證實'wrapper'不是零?另外,我同意vfn關於設置中斷點...... – 2011-11-11 14:51:16

回答

5

你的假設是在創建錯誤車道,在「kSecAttrAccount」和「kSecValueData」未設置爲零。它們被設置爲一個空字符串(即「」)。因此,該代碼將返回true:

[username isEqualToString:@""] // returns true on creation 
+1

而不是直接進行字符串比較,檢查長度的工作也是如此。 '[用戶名長度]> 0' – orkoden 2014-05-19 10:06:45

8
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Test" accessGroup:nil]; 
NSString *username = [wrapper objectForKey:(id)kSecAttrAccount]; 
NSString *password = [wrapper objectForKey:(id)kSecValueData]; 

// initially all these are empty 
NSLog(@"username - %@", username); // username - 
NSLog(@"password - %@", password); // password - 

//if empty set your credentials 
if ([username isEqualToString:@""]) { 
    [wrapper setObject:@"your username here" forKey:(id)kSecAttrAccount]; 
} 
if ([password isEqualToString:@""]) { 
    [wrapper setObject:@"your password here" forKey:(id)kSecValueData]; 
} 

//get the latest credentials - now you have the set values 
username = [wrapper objectForKey:(id)kSecAttrAccount]; 
password = [wrapper objectForKey:(id)kSecValueData]; 

NSLog(@"username - %@", username); // username - your username here 
NSLog(@"password - %@", password); // password - your password here 

// reset your keychain items - if needed 
[wrapper resetKeychainItem]; 
[wrapper release]; 
+0

我不確定的部分是「最初所有這些都是空的」。正如我的問題所提到的,我無法讓'NSLog'打印任何這些值。我試圖調出登錄對話框,如果它們爲空/零,但它不起作用。 – 2010-09-10 09:21:23

0

如果值是零最初使用

if ([username isEqualToString:@""]) 

將評估爲FALSE。你可以使用

if (!username) 

代替

1

我同樣的錯誤,我在KeychainItemWrapper.m文件檢查返回值writeToKeychain功能。返回值等於errSecDuplicateItem。我不知道爲什麼,但似乎SecItemCopyMatching功能無法正常工作。 (對於我的其他項目正常工作)。

我改變代碼爲現在和我一起工作: 爲writeToKeychain更新代碼在KeychainItemWrapper.m文件:

- (void)writeToKeychain 
{ 
    NSDictionary *attributes = NULL; 
    NSMutableDictionary *updateItem = NULL; 
    OSStatus result; 



    if (SecItemCopyMatching((CFDictionaryRef)genericPasswordQuery, (CFTypeRef *)&attributes) == noErr) 
    { 
     // First we need the attributes from the Keychain. 
     updateItem = [NSMutableDictionary dictionaryWithDictionary:attributes]; 
     // Second we need to add the appropriate search key/values. 
     [updateItem setObject:[genericPasswordQuery objectForKey:(id)kSecClass] forKey:(id)kSecClass]; 

     // Lastly, we need to set up the updated attribute list being careful to remove the class. 
     NSMutableDictionary *tempCheck = [self dictionaryToSecItemFormat:keychainItemData]; 
     [tempCheck removeObjectForKey:(id)kSecClass]; 

#if TARGET_IPHONE_SIMULATOR 
     // Remove the access group if running on the iPhone simulator. 
     // 
     // Apps that are built for the simulator aren't signed, so there's no keychain access group 
     // for the simulator to check. This means that all apps can see all keychain items when run 
     // on the simulator. 
     // 
     // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the 
     // simulator will return -25243 (errSecNoAccessForItem). 
     // 
     // The access group attribute will be included in items returned by SecItemCopyMatching, 
     // which is why we need to remove it before updating the item. 
     [tempCheck removeObjectForKey:(id)kSecAttrAccessGroup]; 
#endif 

     // An implicit assumption is that you can only update a single item at a time. 

     result = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck); 
     NSAssert(result == noErr, @"Couldn't update the Keychain Item."); 
    } 
    else 
    { 
     // No previous item found; add the new one. 

     result = SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL); 
     NSLog(@"%@",keychainItemData); 
     NSLog(@"res : %ld",result); 
     if(result == (OSStatus)errSecDuplicateItem) 
     { 
      NSLog(@"updttttt"); 
      // First we need the attributes from the Keychain. 
      updateItem = [NSMutableDictionary dictionaryWithDictionary:attributes]; 
      // Second we need to add the appropriate search key/values. 
      [updateItem setObject:[genericPasswordQuery objectForKey:(id)kSecClass] forKey:(id)kSecClass]; 

      // Lastly, we need to set up the updated attribute list being careful to remove the class. 
      NSMutableDictionary *tempCheck = [self dictionaryToSecItemFormat:keychainItemData]; 
      [tempCheck removeObjectForKey:(id)kSecClass]; 

#if TARGET_IPHONE_SIMULATOR 
      // Remove the access group if running on the iPhone simulator. 
      // 
      // Apps that are built for the simulator aren't signed, so there's no keychain access group 
      // for the simulator to check. This means that all apps can see all keychain items when run 
      // on the simulator. 
      // 
      // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the 
      // simulator will return -25243 (errSecNoAccessForItem). 
      // 
      // The access group attribute will be included in items returned by SecItemCopyMatching, 
      // which is why we need to remove it before updating the item. 
      [tempCheck removeObjectForKey:(id)kSecAttrAccessGroup]; 
#endif 

      // An implicit assumption is that you can only update a single item at a time. 

      result = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck); 
      NSAssert(result == noErr, @"Couldn't update the Keychain Item."); 
      return; 
     }//if(result == errSecDuplicateItem)* 
     NSAssert(result == noErr, @"Couldn't add the Keychain Item."); 
    } 
}