【发布时间】:2013-06-23 13:31:57
【问题描述】:
我有一个方法,它返回一个名为“Credential”的自定义对象的 NSArray,它有两个属性:一个 NSString 和一个 CFDataRef。
您已经注意到该对象有两种类型的属性,一个 NS Objective-C 属性和一个 Core-Foundation 属性。
对象在每次交互循环时都会被初始化,因为它会像这样填充 NSArray:
cred = [[Credential alloc] init];
cred.cn = [NSString stringWithString:(__bridge NSString *)(summary)];
cred.serialNumber = CFDataCreateCopy(kCFAllocatorDefault, serialNumber);
当我运行分析器时,我收到以下消息:
Object leaked: allocated object is not referenced later in this
execution path and has a retain count of +1
我假设发生此警告是因为我正在初始化一个 CF 对象并从该方法返回而不释放它,但是负责释放该对象的 new 应该 是调用该方法的代码。
我应该在哪里调用 Credential 类的 CFDataRef 属性的 CFRelease?
编辑:
我正在使用 ARC,所以我将释放 NSString (cred.cn) 的责任留给他。但是,关于 CFDataRef (cred.serialNumber),我没有发布它,因为稍后我会从另一个类和部分代码中需要它。然后,我不确定如何管理它。当对象“凭据”被释放时,ARC 是否会释放它?如果没有,我可以覆盖 Credential 的 dealloc 方法来做 serialNumber 的 CFRelease 吗?
下面是初始化并返回 Credential 对象的 NSArray 的完整方法:
- (NSArray *) retrieveIdentities
{
CFArrayRef identities = NULL;
NSMutableArray *returnIdentities = nil;
OSStatus sanityCheck = NULL;
const void *keys[] = {kSecClass, kSecMatchLimit, kSecReturnRef, kSecReturnData, kSecReturnAttributes};
const void *values[] = {kSecClassIdentity, kSecMatchLimitAll, kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue};
CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, sizeof(values)/sizeof(const void *), NULL, NULL);
sanityCheck = SecItemCopyMatching(query, (CFTypeRef *)&identities);
if (query)
CFRelease(query);
if (sanityCheck == errSecItemNotFound)
return nil;
if (sanityCheck != noErr)
@throw [[KeychainException alloc] initWithName:@"KeychainException" reason:@"ERROR_LISTING_IDENTITIES" userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithLong: sanityCheck], @"osstatus", nil]];
CFDictionaryRef result = NULL;
CFStringRef summary = NULL;
SecCertificateRef certificate = NULL;
CFDataRef serialNumber = NULL;
Credential *cred = nil;
CFIndex resultCount = CFArrayGetCount(identities);
returnIdentities = [[NSMutableArray alloc] init];
for (CFIndex i = 0; i<resultCount; i++)
{
result = CFArrayGetValueAtIndex(identities,i);
SecIdentityRef identity = (SecIdentityRef) CFDictionaryGetValue(result, kSecValueRef);
if ((sanityCheck = SecIdentityCopyCertificate(identity, &certificate)) != noErr)
@throw [[KeychainException alloc] initWithName:@"KeychainException" reason:@"ERROR_EXTRACTING_CERTIFICATE" userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithLong: sanityCheck], @"osstatus", nil]];
CFTypeRef keyClass = CFDictionaryGetValue(result, kSecAttrKeyClass);
if ([[(__bridge id)keyClass description] isEqual:(__bridge id)(kSecAttrKeyClassPrivate)])
{
summary = SecCertificateCopySubjectSummary(certificate);
serialNumber = CFDataCreateCopy(NULL, CFDictionaryGetValue(result, kSecAttrSerialNumber));
cred = [[Credential alloc] init];
cred.cn = [NSString stringWithString:(__bridge NSString *)(summary)];
cred.serialNumber = CFDataCreateCopy(kCFAllocatorDefault, serialNumber);
[returnIdentities addObject:cred];
if (summary)
CFRelease(summary);
if (serialNumber)
CFRelease(serialNumber);
}
}
if (certificate)
CFRelease(certificate);
return returnIdentities;
}
【问题讨论】:
-
为什么要转换(桥接)刺痛而不是数据?
-
因为我将数据存储为 CFDataRef 对象,因为我以后使用它时需要它。
-
因此,您需要展示如何处理字符串和数据的所有权以及如何释放 CF 对象。
-
我已经用更多(希望有用的)信息编辑了这个问题。
标签: ios objective-c memory-management automatic-ref-counting core-foundation