首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >返回带有核心基础属性的object对象

返回带有核心基础属性的object对象
EN

Stack Overflow用户
提问于 2013-06-26 12:08:02
回答 3查看 1.9K关注 0票数 2

我有一个方法,它返回一个名为“凭证”的自定义对象的NSArray,它有两个属性:一个NSString和一个CFDataRef。

正如您注意到的,对象有两种类型的属性,一个是NS object属性,另一个是Core-Foundation属性。

对象在每个interation循环中都被初始化,因为它填充了NSArray,如下所示:

代码语言:javascript
复制
cred = [[Credential alloc] init];
cred.cn = [NSString stringWithString:(__bridge NSString *)(summary)];
cred.serialNumber = CFDataCreateCopy(kCFAllocatorDefault, serialNumber);

当我运行分析器时,我得到的信息是:

代码语言:javascript
复制
Object leaked: allocated object is not referenced later in this 
execution path and has a retain count of +1

我假设发生此警告是因为我正在初始化一个CF对象,并在没有释放它的情况下从方法返回,但是新的负责释放对象的代码应该是调用该方法的代码。

我应该在哪里调用凭证类的CFRelease属性的CFDataRef属性?

编辑:

我正在使用ARC,所以我留给他发布NSString (cred.cn)的责任。但是,关于CFDataRef (cred.serialNumber),我不会发布它,因为稍后我将从另一个类和代码的一部分中需要它。那么,我不知道如何处理它。在释放对象“凭据”时ARC是否释放它?如果没有,我是否可以重写证书的dealloc方法,以便在那里执行CFRelease of serialNumber?

下面是初始化和返回凭据对象的NSArray的完整方法:

代码语言:javascript
复制
- (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;
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-06-26 23:33:14

带着线

代码语言:javascript
复制
cred.serialNumber = CFDataCreateCopy(kCFAllocatorDefault, serialNumber);

CFDataCreateCopy创建一个具有+1保留计数的对象,在此之后您将不会释放它。这就是为什么分析器警告你。

用下面的代码替换该行应该会修复它

代码语言:javascript
复制
CFDataRef sn = CFDataCreateCopy(kCFAllocatorDefault, serialNumber);
cred.serialNumber = sn;
CFRelease(sn);

关键是,您正在处理所有权,因此会使分析器混淆。

您需要在当前的范围内发布用创建的任何对象,复制或保留中的函数,所以您确实应该释放使用CFDataCreateCopy创建的对象。

如果Credential实例需要保留分配给serialNumber的值,那么应该由他来负责,而不是调用者。要做到这一点,只需将CredentialCredential属性声明为strongcopy,并让ARC发挥其魔力。

编辑

由于从注释中可以看出serialNumber属性具有CFDataRef类型,所以仍然必须通过在可保留对象指针中提交Credential对象来保留它,如下所示

代码语言:javascript
复制
@property (nonatomic, strong) __attribute__((NSObject)) CFDataRef serialNumber;

NSObject属性将使编译器将其作为一个对象来处理,内存管理是明智的。这在clang文档中得到了很好的解释。

票数 1
EN

Stack Overflow用户

发布于 2013-06-26 14:33:23

如果使用CF函数创建的字符串意味着您拥有它,则应该将所有权转移到ARC。目前,您只是连接引用ARC将不会取得所有权。

对于数据,您需要覆盖dealloc并对数据调用CFRelease

分析器不完美。有些事情它觉得很难,所以它犯了错误,过于谨慎,并告诉你可能有问题。

当然,尤其是在泄漏和内存管理方面,您应该使用Instruments来检查正在发生的事情。

票数 2
EN

Stack Overflow用户

发布于 2013-06-26 23:59:57

正如其他人所指出的,您创建了两个序列号副本,但只发布了一个。

您可以将CF对象转换为对应的NS对象,并使用宏CFBridgingRelease负责释放CF对象。发布发生在语句的末尾,在ARC保留了对象之后,如果需要的话。

代码语言:javascript
复制
NSString *summary = CFBridgingRelease(SecCertificateCopySubjectSummary(certificate));
NSData *serialNumber = CFBridgingRelease(CFDictionaryGetValue(result, kSecAttrSerialNumber));
cred = [[Credential alloc] init];
cred.cn = [summary copy];
cred.serialNumber = [serialNumber copy];

基本规则是您可以使用CFBridgingRelease而不是CFRelease。它平衡CF创建或复制函数中的returns,并返回ARC将处理的目标-C对象引用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17319590

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档