从一个返回NSArray的方法中返回NSMutableArray对象

11

当从使用NSMutableArray动态构建数组的方法返回NSArray(或NSDictionary等)时,如何遵循标准方式并在使用ARC时避免随机内存泄漏?

例如,我们有一个带有名称列表的类,并且我们想要手动过滤并获取所有以给定字母开头的名称:

- (NSArray *)getNamesByFirstLetter:(NSString *)firstLetter 
{
    NSMutableArray *returnValue = [[NSMutableArray alloc] init];
    for(id item in self.names)
    {
        if([item hasPrefix:firstLetter])
        {
            [returnValue addObject:item];
        }
    }        
    return returnValue; // just return the above array
}

谈到返回值,我能想到四种可能的方法:

  1. 直接返回NSMutableArray(如上所示)

return returnValue;
  • 返回一个副本

    return [returnValue copy];
    
  • 使用NSArray arrayWithArray进行返回:

    return [NSArray arrayWithArray:returnValue];
    
  • 创建一个NSArray,手动将NSMutableArray设置为nil

    NSArray *temp = [NSArray arrayWithArray:returnValue]; // could use [returnValue copy] here too
    returnValue = nil;
    return temp;
    
    当程序使用ARC时,这四种方法之间是否有任何实际区别,还是只是个人喜好的问题?
    此外,除了可能存在内存泄漏之外,使用一种方法而不是另一种方法还有其他影响吗?
    请注意,如果这是一个重复的问题,请让我知道,我会把这个问题撤下。我试着搜索过,但很难用几个关键词概括这个问题。

  • 3
    不细说,启用ARC时,这些都不会导致内存泄漏。但必须提到的是,在ARC环境中,4和3是等效的。 - Jack
    3个回答

    9
    你提供的四个选项都可以在开启ARC时正常工作(即你提出的解决方案不会导致内存泄漏)。
    但是,你列出的4个解决方案有一些微小的差异。第1种方法将返回一个NSMutableArray,这通常不会导致问题,因为NSMutableArray将响应与NSArray相同的所有消息(但返回的对象将是可变的,这可能不是你想要的)。
    选项2和选项3&4之间存在微妙的差异(在ARC下它们是相同的)。如果returnValue为nil,则选项2将返回nil,但选项3&4将返回一个空的NSArray。(任何一种行为都可能是可取的;你应该决定该方法的行为方式)。此外,-copy可能比+arrayWithArray更快。
    我会选择选项2。

    有道理。我只是太习惯于使用垃圾回收环境了,所以可能有点多虑。此外,进一步的研究引导我看到了这个问题这个问题,它们说arrayWithArray被明确设置为自动释放,而copy则不一定。可以安全地假设这种差异只在不使用ARC的程序中才有影响吗? - valverij
    在垃圾回收的环境中,设置变量为“null”不是必要的(甚至不可取)。此外,ARC将自动释放和常规释放之间的差异对程序员进行了隐藏,因此,在使用ARC编译时,可以安全地忽略这种特定差异。 - Sergey Kalinichenko
    @dasblinkenlight,我知道垃圾回收环境不需要你显式地将变量设置为“null”,这就是为什么我担心在Objective-C中会错过某些东西。不过还是谢谢你,很高兴知道ARC已经覆盖了所有这些内容。 - valverij

    3
    首先,讨论的所有方法在ARC下都不会导致内存泄漏。此外,第四种方法不需要您将returnValue设置为nil - 编译器足够聪明,能够自己处理returnValue。这使得第四种方法与第三种方法完全相同。
    另外,调用returnValue上的copy等同于从其内容创建一个新数组,因此第二种方法与最后两种方法相同。
    这留下了两种方法 - 第一种和第二/第三/第四种。它们之间的主要区别在于用户可以通过您的方法获取到的数组可以做什么。第一种方法允许用户修改数组;后面三种则不行。决定使用哪种行为取决于您。

    1
    错误,数字2会返回一个NSArray,而不是NSMutableArray,因为调用的是copy而不是mutableCopy - Gavin
    所以基本上2、3和4都是一样的。 - Gavin

    0

    除了给定示例中没有泄漏之外,有一件事是每个人都知道的,那就是NSArray可能是可变的。如果将其作为方法调用的结果获取,则由您决定是复制它还是使用原样,并准备随时更改。这就是为什么不可变属性经常声明为副本而不是强引用的原因。将可变值分配给该属性将进行真正的副本,而将不可变值分配给该属性则很便宜。

    tl;dr:只需返回returnValue,没问题。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接