说明:
每一个keyChain的组成如图,整体是一个字典结构.
1.kSecClass key 定义属于那一种类型的keyChain
2.不同的类型包含不同的Attributes,这些attributes定义了这个item的具体信息
3.每个item可以包含一个密码项来存储对应的密码
使用:
引入Security包,引入文件 #import
添加
- (IBAction)add:(id)sender {
if (nameField.text.length > 0 && passwordField.text.length > 0) {
// 一个mutable字典结构存储item信息
NSMutableDictionary* dic = [NSMutableDictionary dictionary];
// 确定所属的类class
[dic setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
// 设置其他属性attributes
[dic setObject:nameField.text forKey:(id)kSecAttrAccount];
// 添加密码 secValue 注意是object 是 NSData
[dic setObject:[passwordField.text dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData];
// SecItemAdd
OSStatus s = SecItemAdd((CFDictionaryRef)dic, NULL);
NSLog(@"add : %ld",s);
}
}
查找
// 查找全部
- (IBAction)sel:(id)sender {
NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass,
kSecMatchLimitAll,kSecMatchLimit,
kCFBooleanTrue,kSecReturnAttributes,nil];
CFTypeRef result = nil;
OSStatus s = SecItemCopyMatching((CFDictionaryRef)query, &result);
NSLog(@"se;ect all : %ld",s);
NSLog(@"%@",result);
}
// 按名称查找
- (IBAction)sname:(id)sender {
if (nameField.text.length >0) {
// 查找条件:1.class 2.attributes 3.search option
NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass,
nameField.text,kSecAttrAccount,
kCFBooleanTrue,kSecReturnAttributes,nil];
CFTypeRef result = nil;
// 先找到一个item
OSStatus s = SecItemCopyMatching((CFDictionaryRef)query, &result);
NSLog(@"select name : %ld",s); // errSecItemNotFound 就是找不到
NSLog(@"%@",result);
if (s == noErr) {
// 继续查找item的secValue
NSMutableDictionary* dic = [NSMutableDictionary dictionaryWithDictionary:result];
// 存储格式
[dic setObject:(id)kCFBooleanTrue forKey:kSecReturnData];
// 确定class
[dic setObject:[query objectForKey:kSecClass] forKey:kSecClass];
NSData* data = nil;
// 查找secValue
if (SecItemCopyMatching((CFDictionaryRef)dic, (CFTypeRef*)&data) == noErr) {
if (data.length)
NSLog(@"%@",[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);
}
}
}
}
修改
- (IBAction)update:(id)sender {
if (nameField.text.length >0 && passwordField.text.length > 0) {
// 先查找看看有没有
NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass,
nameField.text,kSecAttrAccount,
kCFBooleanTrue,kSecReturnAttributes,nil];
CFTypeRef result = nil;
if (SecItemCopyMatching((CFDictionaryRef)query, &result) == noErr)
{
// 更新后的数据,基础是搜到的result
NSMutableDictionary* update = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary*)result];
// 修改要跟新的项 注意先加后删的class项
[update setObject:[query objectForKey:kSecClass] forKey:kSecClass];
[update setObject:[passwordField.text dataUsingEncoding:NSUTF8StringEncoding] forKey:kSecValueData];
[update removeObjectForKey:kSecClass];
#if TARGET_IPHONE_SIMULATOR
// 模拟器的都有个默认的组“test”,删了,不然会出错
[update removeObjectForKey:(id)kSecAttrAccessGroup];
#endif
// 得到要修改的item,根据result,但要添加class
NSMutableDictionary* updateItem = [NSMutableDictionary dictionaryWithDictionary:result];
[updateItem setObject:[query objectForKey:(id)kSecClass] forKey:(id)kSecClass];
// SecItemUpdate
OSStatus status = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)update);
NSLog(@"update:%ld",status);
删除
- (IBAction)del:(id)sender {
if (nameField.text.length >0) {
// 删除的条件
NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass,
nameField.text,kSecAttrAccount,nil];
// SecItemDelete
OSStatus status = SecItemDelete((CFDictionaryRef)query);
NSLog(@"delete:%ld",status); // // errSecItemNotFound 就是没有
}
}
注意:
1.区别(标识)一个item要用kSecAttrAccount和kSecAttrService