词典的深度复制在Xcode 4.2中给出了分析错误 [英] Deep copy of dictionaries gives Analyze error in Xcode 4.2

查看:174
本文介绍了词典的深度复制在Xcode 4.2中给出了分析错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我刚刚从Xcode 4.1升级到4.2,并且分析函数为此代码提供两个分析器警告,如下所示:

   - (id)deepCopy; 
{
id dict = [[NSMutableDictionary alloc] init];
id copy;

for(id key in self)
{
id object = [self objectForKey:key];

if([object respondingToSelector:@selector(deepCopy)])
copy = [object deepCopy];
else
copy = [object copy];

[dict setObject:copy forKey:key];

// -deepCopy和-copy保留对象,-setObject:forKey :,因此需要-release:
[copy release]; // Xcode 4.2的分析说这是一个不正确的引用计数减少?
}

return dict; // Xcode 4.2的分析说这是一个潜在的泄漏
}

这些错误在Xcode的分析器中,还是有更改我可以避免这些警告?



我还没有使用ARC,虽然我有兴趣,如果有额外的更改需要支持ARC。

解决方案

可能是因为 deepCopy 不会以 copy 开头。



因此,您可能要更改为像 copyWithDeepCopiedValues (或类似的东西),然后看看分析仪是否标记。



更新



如Alexsander所说,您可以使用属性来表示引用计数的目的。这应该(IMO)是规则的例外,并且很少使用,如果有的话。个人来说,我不会使用objc方法的属性,因为它很脆弱。



到目前为止,我使用的唯一属性是 consume ,每次我使用这些属性都在静态类型的上下文中(例如C函数和C ++函数和方法)。



如果可能:



1)坚持程序员的习惯。代码更清晰,您不需要参考文档。



2)这种方法很脆弱。您仍然可以引入引用计数不平衡,并且属性可用于引入由于属性冲突导致的构建错误。



以下情况都是使用ARC启用的:



案例#1

  #import< ; Foundation / Foundation.h> 

@interface MONType:NSObject

- (NSString *)string __attribute __((objc_method_family(copy)));

@end

@implementation MONType

- (NSString *)string
{
NSMutableString * ret = [NSMutableString新];
[ret appendString:@MONType];
return ret;
}

@end

int main(int argc,const char * argv [])
{
@autoreleasepool {
id obj = nil;
if(random()%2U){
obj = [[NSAttributedString alloc] initWithString:@NSAttributedString];
}
else {
obj = [MONType new];
}
NSLog(@Result:%@,%@,obj,[obj string]);
}
/ *这个工具的名字是ARC,dump the leaks:* /
system(leaks ARC);
return 0;
}

此程式产生以下错误:方法命名为'string'发现不匹配的结果,参数类型或属性

$



很好,编译器做了什么可以防止这些问题。这意味着属性中的冲突可以基于翻译引入错误。这是,因为当非重要的代码库组合和属性冲突,您将有错误纠正和程序更新。



第2种情况



Header.h

  extern id NewObject 

Header.m

  #import< Foundation / Foundation.h> 
#importHeader.h

@interface MONType:NSObject

- (NSString *)string __attribute __((objc_method_family(copy)));

@end

@implementation MONType

- (NSString *)string
{
NSMutableString * ret = [NSMutableString新];
[ret appendString:@ - [MONType string]];
return ret;
}

@end


id NewObject(void){
id obj = nil;
if(random()%2U){
obj = [[NSAttributedString alloc] initWithString:@NSAttributedString];
}
else {
obj = [MONType new];
}
return obj;
}

main.m

  #import< Foundation / Foundation.h> 
#importHeader.h

int main(int argc,const char * argv [])
{
@autoreleasepool {
for size_t idx = 0; idx <8; ++ idx){
id obj = NewObject();
NSLog(@Result:%@,%@,obj,[obj string]);
}
}
/ *这个工具的名字是ARC,dump the leaks:* /
system(leaks ARC);
return 0;
}

好的。这只是。我们引入了泄漏,因为翻译单元中没有必要的信息。这是泄漏报告:

  leaks报告版本:2.0 
过程7778:1230节点为210 KB
过程7778:4个泄漏,共192个泄漏字节。
Leak:0x1005001f0 size = 64 zone:DefaultMallocZone_0x100003000 __NSCFString ObjC CoreFoundation可变非内联: - [MONType string]
泄漏:0x100500320 size = 64 zone:DefaultMallocZone_0x100003000 __NSCFString ObjC CoreFoundation mutable non-inline: - [MONType string]
Leak:0x100500230 size = 32 zone:DefaultMallocZone_0x100003000 has-length-byte: - [MONType string]
Leak:0x100500390 size = 32 zone:DefaultMallocZone_0x100003000 has-length-byte : - [MONType string]

注意:计数可能有所不同,因为我们使用 random()



这意味着 MONType code> main(),编译器将ARC属性绑定到当前TU可见的方法(即 string 基金会的声明,所有这些都遵循惯例)。因此,编译器错误,我们可以在程序中引入泄漏。



案例3



使用类似的方法,我也能够引入负引用计数不平衡(过早释放,或一个消息僵尸)。



注意:



您可以避免所有这些问题,并通过坚持约定而不是使用属性来提高可读性和可维护性。



将对话带回到非ARC代码:使用属性使得手动内存管理对于程序员的可读性和帮助您的工具(例如,编译器,静态分析)。如果程序是相当复杂的,使工具不能检测这样的错误,那么你应该重新考虑你的设计,因为它会同样复杂,你或其他人来调试这些问题。


I have the following method in a NSDictionary category, to do a deep copy, which works fine.

I just upgraded from Xcode 4.1 to 4.2, and the Analyze function gives two analyzer warnings for this code, as indicated:

- (id)deepCopy;
{
    id dict = [[NSMutableDictionary alloc] init];
    id copy;

    for (id key in self)
    {
        id object = [self objectForKey:key];

        if ([object respondsToSelector:@selector(deepCopy)])
            copy = [object deepCopy];
        else
            copy = [object copy];

        [dict setObject:copy forKey:key];

        // Both -deepCopy and -copy retain the object, and so does -setObject:forKey:, so need to -release:
        [copy release];  // Xcode 4.2's Analyze says this is an incorrect decrement of the reference count?!
    }

    return dict;  // Xcode 4.2's Analyze says this is a potential leak
}

Are these bugs in Xcode's analyzer, or are there changes I can make to avoid these warnings?

I'm not using ARC yet, though I am interested if there are additional changes needed to support ARC for this method.

解决方案

Presumably, it is because deepCopy does not begin with the prefix copy.

So you may want to change to something like copyWithDeepCopiedValues (or something like that), and then see if the analyzer flags that.

Update

As Alexsander noted, you can use attributes to denote reference counting intent. This should (IMO) be the exception to the rule, and used rarely, if ever. Personally, I will not use attributes for objc methods because it is fragile.

The only attribute I have used so far has been consume, and every time I use these attributes has been in statically typed contexts (e.g. C functions and C++ functions and methods).

The reasons you should avoid attributes when possible:

1) Stick with conventions for the programmers' sake. The code is clearer and you do not need to refer to the documentation.

2) The approach is fragile. You can still introduce reference count imbalances, and attributes can be used to introduce build errors due to conflicts in attributes.

The following cases are all built with ARC enabled:

Case #1

#import <Foundation/Foundation.h>

@interface MONType : NSObject

- (NSString *)string __attribute__((objc_method_family(copy)));

@end

@implementation MONType

- (NSString *)string
{
    NSMutableString * ret = [NSMutableString new];
    [ret appendString:@"MONType"];
    return ret;
}

@end

int main (int argc, const char * argv[])
{
    @autoreleasepool {
        id obj = nil;
        if (random() % 2U) {
            obj = [[NSAttributedString alloc] initWithString:@"NSAttributedString"];
        }
        else {
            obj = [MONType new];
        }
        NSLog(@"Result: %@, %@", obj, [obj string]);
    }
    /* this tool's name is ARC, dump the leaks: */
    system("leaks ARC");
    return 0;
}

This program produces the following error: error: multiple methods named 'string' found with mismatched result, parameter type or attributes.

Great, the compiler's doing what it can to prevent these issues. What that means is that conflicts in attributes can introduce errors based on the translation. This is bad because when nontrivial codebases are combined and attributes conflict, you will have errors to correct and programs to update. This also means that simply including other libraries in translation units can break existing programs when attributes are used.

Case #2

Header.h

extern id NewObject(void);

Header.m

#import <Foundation/Foundation.h>
#import "Header.h"

@interface MONType : NSObject

- (NSString *)string __attribute__((objc_method_family(copy)));

@end

@implementation MONType

- (NSString *)string
{
    NSMutableString * ret = [NSMutableString new];
    [ret appendString:@"-[MONType string]"];
    return ret;
}

@end


id NewObject(void) {
    id obj = nil;
    if (random() % 2U) {
        obj = [[NSAttributedString alloc] initWithString:@"NSAttributedString"];
    }
    else {
        obj = [MONType new];
    }
    return obj;
}

main.m

#import <Foundation/Foundation.h>
#import "Header.h"

int main (int argc, const char * argv[])
{
    @autoreleasepool {
        for (size_t idx = 0; idx < 8; ++idx) {
            id obj = NewObject();
            NSLog(@"Result: %@, %@", obj, [obj string]);
        }
    }
    /* this tool's name is ARC, dump the leaks: */
    system("leaks ARC");
    return 0;
}

Ok. This is just bad. We've introduced leaks because the necessary information was not available in the translation unit. Here's the leaks report:

leaks Report Version:  2.0
Process 7778: 1230 nodes malloced for 210 KB
Process 7778: 4 leaks for 192 total leaked bytes.
Leak: 0x1005001f0  size=64  zone: DefaultMallocZone_0x100003000   __NSCFString  ObjC  CoreFoundation  mutable non-inline:  "-[MONType string]"
Leak: 0x100500320  size=64  zone: DefaultMallocZone_0x100003000   __NSCFString  ObjC  CoreFoundation  mutable non-inline:  "-[MONType string]"
Leak: 0x100500230  size=32  zone: DefaultMallocZone_0x100003000  has-length-byte:  "-[MONType string]"
Leak: 0x100500390  size=32  zone: DefaultMallocZone_0x100003000  has-length-byte:  "-[MONType string]"

note: the count may differ because we used random()

This means that because MONType is not visible to main(), the compiler bound the ARC properties to methods which were visible to the current TU (that is, string from declarations in Foundation, all of which follow convention). As a result, the compiler got it wrong and we were able to introduce leaks into our program.

Case 3

Using a similar approach, I was also able to introduce negative reference count imbalances (premature releases, or a messaged zombie).

note: Code not provided because Case #2 already illustrates how one can accomplish a reference count imbalance.

Conclusion

You can avoid all these problems and improve readability and maintainability by sticking with convention, rather than using attributes.

Bringing the conversation back to non-ARC code: Using attributes makes manual memory management more difficult for programmers' readability, and for the tools which are there to help you (e.g. compiler, static analysis). If the program is suitably complex such that the tools can't detect such errors, then you should reconsider your design, because it will be equally complex for you or somebody else to debug these issues.

这篇关于词典的深度复制在Xcode 4.2中给出了分析错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆