字典的深层副本在 Xcode 4.2 中给出了分析错误 [英] Deep copy of dictionaries gives Analyze error in Xcode 4.2

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

问题描述

我在 NSDictionary 类别中有以下方法来进行深度复制,效果很好.

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

我刚刚从 Xcode 4.1 升级到 4.2,分析函数针对这段代码给出了两个分析器警告,如下所示:

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
}

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

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

我还没有使用 ARC,但我很感兴趣是否需要进行其他更改来支持此方法的 ARC.

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

推荐答案

大概是因为deepCopy没有begin前缀copy.

因此,您可能想要更改为类似 copyWithDeepCopiedValues(或类似内容)的内容,然后查看分析器是否标记了该内容.

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

更新

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

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.

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

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) 为了程序员的利益,坚持约定.代码更清晰,无需参考文档.

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

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

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.

以下案例都是在启用ARC的情况下构建的:

The following cases are all built with ARC enabled:

案例#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;
}

此程序产生以下错误:error: multiple methods named 'string' found with mismatched result, parameter type or attributes.

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.

案例#2

标题.h

extern id NewObject(void);

标题.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]"

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

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

这意味着因为 MONTypemain() 不可见,编译器将 ARC 属性绑定到对当前 TU 可见的方法(即 string 来自 Foundation 中的声明,所有这些都遵循约定).结果,编译器出错了,我们能够在我们的程序中引入泄漏.

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.

案例 3

使用类似的方法,我还能够引入负引用计数不平衡(过早发布或消息僵尸).

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

注意:未提供代码,因为案例 #2 已经说明了如何实现引用计数不平衡.

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

结论

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

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

将话题带回到非 ARC 代码上:使用属性会使手动内存管理对于程序员的可读性以及可帮助您的工具(例如编译器、静态分析)变得更加困难.如果程序相当复杂,以至于工具无法检测到此类错误,那么您应该重新考虑您的设计,因为调试这些问题对您或其他人来说同样复杂.

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天全站免登陆