IOS KeyChain理解及代碼案例
對KeyChain的理解,可參照http://my.oschina.net/w11h22j33/blog/206713
文中利用KeyChain儲存使用者名稱和密碼,使用者名稱放在屬性中,密碼放在密碼項中;其中對KeyChain項的增刪改查,我個人覺得是有問題的,為了方面自己代碼上的使用,也協助閱讀該文的其他讀者更好的理解,我修正了代碼如下:
//儲存/增加-(IBAction)saveClicked:(id)sender{ if(_nameTF.text.length > 0 && _psdTF.text.length > 0) { NSMutableDictionary* dic = [NSMutableDictionary dictionary]; [dic setObject:(__bridge_transfer id)kSecClassGenericPassword forKey:(__bridge_transfer id)kSecClass]; [dic setObject:_nameTF.text forKey:(__bridge_transfer id)kSecAttrAccount]; [dic setObject:[_psdTF.text dataUsingEncoding:NSUTF8StringEncoding] forKey:(__bridge_transfer id)kSecValueData]; OSStatus s = SecItemAdd((__bridge_retained CFDictionaryRef)dic, NULL); NSLog(@%d,s); }}//擷取/查詢-(IBAction)showClicked:(id)sender{ if(_nameTF.text.length > 0) { NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword, (__bridge_transfer id)kSecClass, _nameTF.text, (__bridge_transfer id)kSecAttrAccount, kCFBooleanTrue, kSecReturnAttributes,nil]; CFTypeRef result = nil; OSStatus s = SecItemCopyMatching((__bridge_retained CFDictionaryRef)query, &result); NSLog(@%d,s); NSLog(@%@,result); if(s == noErr) {//通過使用者名稱判斷item項是否存在 NSMutableDictionary* dic = [NSMutableDictionary dictionary]; [dic setObject:_nameTF.text forKey: (__bridge_transfer id)kSecAttrAccount]; [dic setObject:(__bridge_transfer id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData]; [dic setObject:(__bridge_transfer id)kSecClassGenericPassword forKey:(__bridge_transfer id)kSecClass]; CFDataRef dataRef = NULL; if(SecItemCopyMatching((__bridge_retained CFDictionaryRef)dic, (CFTypeRef*)&dataRef) == noErr) { NSData *data = (__bridge_transfer id)dataRef; NSLog(@%ld, data.length); NSLog(@%@,[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); } } }else{ NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass, (__bridge_transfer id)kSecMatchLimitAll, (__bridge_transfer id)kSecMatchLimit, (__bridge_transfer id)kCFBooleanTrue,(__bridge_transfer id)kSecReturnAttributes,nil]; CFArrayRef result = NULL; OSStatus s = SecItemCopyMatching((__bridge_retained CFDictionaryRef)query, (CFTypeRef*)&result); NSArray *array = (__bridge_transfer NSArray*)result;//(可以遍曆所有keychain項) NSLog(@%d,s); NSLog(@%@,result); } }//刪除-(IBAction)delClicked:(id)sender{ if(_nameTF.text.length > 0){ NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:(__bridge_transfer id)kSecClassGenericPassword,kSecClass, _nameTF.text,kSecAttrAccount,nil]; OSStatus status = SecItemDelete((__bridge_retained CFDictionaryRef)query); NSLog(@%d,status); }}//改-(IBAction)modifyClicked:(id)sender{ if(_nameTF.text.length > 0 && _psdTF.text.length > 0) { NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword, (__bridge_transfer id)kSecClass, _nameTF.text, (__bridge_transfer id)kSecAttrAccount, (__bridge_transfer id)kCFBooleanTrue, (__bridge_transfer id)kSecReturnAttributes,nil]; CFTypeRef result = nil; if(SecItemCopyMatching((__bridge_retained CFDictionaryRef)query, &result) == noErr)//存在才修改 { //設定需要更新的屬性列表,一定要刪除kSecClass,因為不能update不該欄位,否則會報錯 NSMutableDictionary* update = [[NSMutableDictionary alloc]init]; [update setObject:[_psdTF.text dataUsingEncoding:NSUTF8StringEncoding] forKey:(__bridge_transfer id)kSecValueData]; [update removeObjectForKey:(__bridge_transfer id)kSecClass]; //設定尋找條件,即根據這個條件找到keychain項 NSMutableDictionary* updateItem = [[NSMutableDictionary alloc]init]; [updateItem setObject:[query objectForKey:(__bridge_transfer id)kSecClass] forKey:(__bridge_transfer id)kSecClass]; [updateItem setObject:_nameTF.text forKey:(__bridge_transfer id)kSecAttrAccount]; //參數一表示要查虛的,參數二表示更新後的值 OSStatus status = SecItemUpdate((__bridge_retained CFDictionaryRef)updateItem, (__bridge_retained CFDictionaryRef)update); NSLog(@%d,status); } }}