引用计数对象在发布后使​​用

时间:2012-04-01 17:02:24

标签: iphone objective-c ios memory-leaks

对项目进行代码分析,并在行[defaults setObject:deviceUuid forKey:@“deviceUuid”]上获取消息“引用后使用引用计数对象”;

我看了这个话题 Obj-C, Reference-counted object is used after it is released? 但找不到解决方案。 ARC禁用。

// Get the users Device Model, Display Name, Unique ID, Token & Version Number
UIDevice *dev = [UIDevice currentDevice];
NSString *deviceUuid;
if ([dev respondsToSelector:@selector(uniqueIdentifier)])
    deviceUuid = dev.uniqueIdentifier;
else {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    id uuid = [defaults objectForKey:@"deviceUuid"];
    if (uuid)
        deviceUuid = (NSString *)uuid;
    else {
        CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
        deviceUuid = (NSString *)cfUuid;
        CFRelease(cfUuid);
        [defaults setObject:deviceUuid forKey:@"deviceUuid"];
    }
}

请帮助找到原因。

2 个答案:

答案 0 :(得分:4)

问题在于:

    CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
    deviceUuid = (NSString *)cfUuid;
    CFRelease(cfUuid);
    [defaults setObject:deviceUuid forKey:@"deviceUuid"];

让我们来看看它实际上做了什么:

    CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));

创建(并泄露)CFUUID。创建CFStringRef并将其分配给cfUuid。 (注意:名称cfUuid意味着cfUuid是CFUUIDRef。当然,它不是;它是CFStringRef。)

    deviceUuid = (NSString *)cfUuid;

同样的CFStringRef是类型转换并分配给deviceUuid。这是 NSString或CFStringRef的新实例,它只是相同实例的类型转换。

    CFRelease(cfUuid);

您释放CFStringRef。由于NSString指向同一个对象,因此您也可以释放它。

    [defaults setObject:deviceUuid forKey:@"deviceUuid"];

在这里,您使用之前发布的类型转换对象。

对陈旧指针最简单的解决方法是:

    CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
    deviceUuid = (NSString *)cfUuid;
    [defaults setObject:deviceUuid forKey:@"deviceUuid"];
    CFRelease(cfUuid);

但是这段代码很危险,你已经知道了原因:deviceUuid也是无效的。但这并不明显,所以你以后可以绊倒它。此外,它不能解决CFUUID泄漏问题。

要修复CFStringRef泄漏,可以使用:

    deviceUuid = (NSString *)CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
    [defaults setObject:deviceUuid forKey:@"deviceUuid"];
    [deviceUuid autorelease]; // or release, if you don't need it in code not
                              // included in your post

但是,这仍然无法修复CFUUID泄漏。

    CFUUIDRef cfuuid = CFUUIDCreate(NULL);
    deviceUuid = (NSString *)CFUUIDCreateString(NULL, cfuuid);
    CFRelease(cfuuid);
    [defaults setObject:deviceUuid forKey:@"deviceUuid"];
    [deviceUuid autorelease]; // or release, if you don't need it in code not
                              // included in your post

答案 1 :(得分:1)

问题出在这里:

CFRelease(cfUuid); 

你不应该释放它,你应该在完成后释放deviceUuid