2012-04-01 31 views
1

对该项目进行代码分析并获得消息“引用计数的对象在发布后使​​用”在行[缺省值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"]; 
    } 
} 

请帮忙找出原因。

+0

我不明白“我的ARC项目”是什么意思。您是否启用了ARC或者您是否已禁用ARC? – 2012-04-01 17:05:12

+0

对不起。 ARC禁用。 – EndyVelvet 2012-04-01 17:07:51

+1

顺便说一句,你可能不应该使用调用UIDevice的uniqueIdentifier方法,因为它已被弃用,它的使用可能会导致你的应用程序在你提交到App Store时被拒绝(根据几个新闻网站) – 2012-04-01 17:27:00

回答

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"]; 

而在这里,您使用之前发布的typecasted对象。

到陈旧的指针简单的解决办法是这样的:

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 
+0

你的回复。在你的第一个例子中,同样的消息,但在行 CFStringRef cfUuid = CFUUIDCreateString(NULL,CFUUIDCreate(NULL)); 第二个示例显示了相同的行,这里是屏幕截图 http://img849.imageshack.us/img849/8519/20120401215928.png – EndyVelvet 2012-04-01 18:00:21

+0

糟糕。我必须稍微修改一下答案。感谢您指出了这一点。 – 2012-04-01 18:25:55

+0

完成。我还应该指出,如果你非常喜欢,这是学习** Objective C Categories **的好地方。所有这些代码都可以写入一个类别。 – 2012-04-01 18:36:22

1

问题就在这里:

CFRelease(cfUuid); 

你不应该释放,你应该释放deviceUuid当你做完这些。

+1

我还补充说,这样分配变量非常容易让人误解 - 为什么不直接执行'deviceUuid =(NSString *)CFUUIDCreateString(NULL,CFUUIDCreate(NULL));' - 这样就不会有模糊性:) – deanWombourne 2012-04-01 17:13:59