问题:在secItemCopyMatching之后,我检查我的NSData对象,以确保它不为空,然后才将其转换为NSString。问题是,它总是为空。下面是我保存keychain条目或更新它的方法,以及我检索它的方法。非常感谢任何帮助和解释。
更新(已编辑):Fruity Geek,感谢您的回复。我使用__bridge更新了代码。现在,我的问题归结为,我是否正确存储和检索密码?我两个都错了还是只有一个错了?我的NSData实例总是为空。我正在检查返回代码,并且我的SecItemAdd和SecItemUpdate(当keychaing条目存在时)都工作正确。我似乎无法检索存储的字符串值(passcode),以将其与用户输入的passcode进行比较。感谢各位的帮助。以下是我现在正在做的:
更新#2:(使用Fruity Geek的回答和最终工作版本进行编辑。我的编辑仅包括对下面代码的更改。)
设置keychain条目:
NSData *secret = [_backupPassword dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: twServiceName,
(__bridge id)kSecAttrAccount: twAccountName,
(__bridge id)kSecValueData: secret,
};
OSStatus status =
SecItemAdd((__bridge CFDictionaryRef)query, NULL);
if (status == errSecDuplicateItem) {
// this item exists in the keychain already, update it
query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: twServiceName,
(__bridge id)kSecAttrAccount: twAccountName,
};
NSDictionary *changes = @{
(__bridge id)kSecValueData: secret,
};
status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)changes);
}
从钥匙串中获取密码:
NSDictionary *query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: twServiceName,
(__bridge id)kSecAttrAccount: twAccountName,
(__bridge id)kSecReturnData: @YES,
};
NSData *data = NULL;
CFTypeRef dataTypeRef = (__bridge CFTypeRef)data;
OSStatus status =
SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef);
NSData *data = (__bridge NSData *)dataTypeRef;
NSString *passcode = @"none";
if (status == errSecSuccess) {
// we found a keychain entry, set the passcode
if (data)
passcode = [NSString stringWithUTF8String:[data bytes]];
}
twServiceName和twAccountName是静态NSStrings。
正如我所说,我对__bridge或CFTypeRef不太了解。我查看了苹果文档、这里和其他站点的许多帖子,但关键链和这些术语对我来说都是全新的,我还在努力弄清楚。希望这里的某个人能指出我的错误并帮助我理解。提前感谢您的帮助。
iOS 7 / Xcode 5