引用计数对象被释放后使用

End*_*vet 1 iphone memory-leaks objective-c ios

对项目进行代码分析,在[defaults setObject: deviceUuid forKey: @“deviceUuid”]行上得到“ Reference-counted object is used after it release”的提示;

我看了这个话题 Obj-C,Reference-counted object 释放后使用? 但是没有找到解决办法。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"];
    }
}
Run Code Online (Sandbox Code Playgroud)

请帮忙找出原因。

Ste*_*her 5

问题在这里:

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

让我们来看看它的实际作用:

    CFStringRef cfUuid = CFUUIDCreateString(NULL, CFUUIDCreate(NULL));
Run Code Online (Sandbox Code Playgroud)

创建(并泄露)一个 CFUUID。CFStringRef 被创建并分配给 cfUuid。(注意:名称 cfUuid 暗示 cfUuid 是一个 CFUUIDRef。当然,它不是;它是一个 CFStringRef。)

    deviceUuid = (NSString *)cfUuid;
Run Code Online (Sandbox Code Playgroud)

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

    CFRelease(cfUuid);
Run Code Online (Sandbox Code Playgroud)

您释放 CFStringRef。由于 NSString 指向同一个对象,因此您也将其释放。

    [defaults setObject:deviceUuid forKey:@"deviceUuid"];
Run Code Online (Sandbox Code Playgroud)

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

对陈旧指针的最简单修复是这样的:

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

但是这段代码很危险,你已经知道为什么了: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
Run Code Online (Sandbox Code Playgroud)

但是,这仍然不能修复 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
Run Code Online (Sandbox Code Playgroud)