我最近将一个庞大的图书馆迁移到了ARC,一个免工具部分令人头疼。这是代码:
+ (NSString *)getKeychainItem:(NSString *)identifier
{
NSString *fullIdentifier = [NSString stringWithFormat:@"%@%@", kIdentifierPrefix, identifier];
NSMutableDictionary *queryKeychain;
OSStatus status = noErr;
queryKeychain = [NSMutableDictionary dictionary];
// Set the public key query dictionary.
[queryKeychain setObject:(__bridge id)kSecClassGenericPassword
forKey:(__bridge id)kSecClass];
// Get the key.
CFDataRef data;
CFDictionaryRef queryKeychainCF = (__bridge CFDictionaryRef)queryKeychain;
status = SecItemCopyMatching(queryKeychainCF, (CFTypeRef *)&data);
NSData *passwordData = (__bridge_transfer NSData *)data;
NSString *password;
if (status == noErr)
{
password = [[NSString alloc] initWithBytes:[passwordData bytes]
length:[passwordData length]
encoding:NSUTF8StringEncoding];
}
else if (status != errSecItemNotFound)
{
NSLog(@"Error getting keychain item %@ -- OSStatus: %lu", identifier, status);
}
return password;
}
这应该是非常简单的,但是,passwordData对象被过度释放,我不知道为什么,堆栈跟踪是this。如果我只是将passwordData
设置为nil
而不执行__bridge__transfer
,则不会崩溃。关于为什么的任何想法?
非常感谢!
答案 0 :(得分:2)
我自己没有使用__bridge_transfer
,但是如果你将“passwordData”更改为:
NSData *passwordData = (NSData *)data;
XCode为您提供了两条建议。
不要转让所有权(核心基金会必须释放它):
NSData *passwordData = (__bridge NSData *)data;
转让所有权(ARC接管):
NSData *passwordData = (NSData *)CFBridgingRelease(data);
__bridge_transfer
可能是同一回事,但我使用CFBridgingRelease
调用时遇到了麻烦,这是XCode推荐的。
将任何内容设置为nil实际上不会释放任何内容,除非ARC正在管理内存。您永远不希望将Core Foundation对象设置为nil,除非您已使用Core Foundation明确发布它,或将所有权转移到ARC。
您拥有的另一个选择是在返回之前执行CFRelease(data)
并使用正常的__bridge
。
这完全基于SecItemCopyMatching
正在为您提供数据副本而不释放它的假设。 New
和Copy
是通常表明这一点的关键字。您可以在不同点使用CFGetRetainCount(data)
进一步调试以验证计数。
我还注意到没有使用fullIdentifier。这是整个功能吗?
您也可以使用initWithData:encoding:
代替initWithBytes:length:encoding
。
答案 1 :(得分:0)
您需要使用
将CFDataRef
投射到NSData
NSData *passwordData = (NSData *)data;
或只是在不转让所有权的情况下使用网桥
NSData* passwordData = (__bridge NSData*) data;
答案 2 :(得分:0)
原来问题出在另一个对象上,附上正确的代码:
CFDictionaryRef queryKeychainCF = (__bridge_retained CFDictionaryRef)queryKeychain;
status = SecItemCopyMatching(queryKeychainCF, (CFTypeRef *)&data);
NSData *passwordData = (__bridge_transfer NSData *)data;
尝试所有解决方案后,开始在ARC下阅读SecItemCopyMatching
方法的错误并进入此answer。