Objective c 返回可变对象与返回不可变(非成员)对象

Objective c 返回可变对象与返回不可变(非成员)对象,objective-c,cocoa,nsmutablearray,Objective C,Cocoa,Nsmutablearray,我几乎从未见过第二个被使用,我想知道为什么 对于预期出现NSArray的情况(因为它是一个子类),它也不会中断支持 它也不会通过揭示可变的内部结构来破坏封装 在不返回可变ivar的前提下(这应该是常识) 我现在只能想到使用第二种方法的好处 它实际上是可变的。静音在这里是安全的,那么为什么要防止呢 无需调用[[[foo fooBar]mutableCopy]autorelease],这会不必要地分配额外的内存,也会不必要地浪费时间 以下是不同的方法: - (NSArray *)fooBar

我几乎从未见过第二个被使用,我想知道为什么

  • 对于预期出现
    NSArray
    的情况(因为它是一个子类),它也不会中断支持
  • 它也不会通过揭示可变的内部结构来破坏封装
在不返回可变ivar的前提下(这应该是常识)
我现在只能想到使用第二种方法的好处

  • 它实际上是可变的。静音在这里是安全的,那么为什么要防止呢
  • 无需调用
    [[[foo fooBar]mutableCopy]autorelease]
    ,这会不必要地分配额外的内存也会不必要地浪费时间
以下是不同的方法:

- (NSArray *)fooBar {
    NSMutableArray *fooArray = [NSMutableArray array];
    //populate fooArray
    return fooArray;
}

- (NSMutableArray *)fooBar {
    NSMutableArray *fooArray = [NSMutableArray array];
    //populate fooArray
    return fooArray;
}
我的问题是,我的项目有一系列具有相同模式的方法
大多数时间中,返回的数组将在之后修改(合并、编辑等)。
因此,我认为返回
nsmutablearray
应该是完全正确的,但是似乎没有人这样做


NSMutableArray
NSMutableSet
NSMutableDictionary
…基本上都是一样的交易。

有关使用可变与不可变的解释,请查看苹果公司的文档

通常,最好返回不可变版本,除非您特别希望返回的对象始终是可供任何客户端更改的不可变对象。您应该根据接口的意图创建接口,而不是脱离当前的实现。需求可能会改变,您需要改变fooBar的实现,以便它返回一个实例变量。通过返回可变数组,您可以确保不仅封装了实例变量,而且封装了当前实现


因此,您可能有一个返回可变数组的有效位置(我不知道),但您会看到大多数代码传递不可变数组,因为它完全封装了它们的变量及其实现。

我认为首选第一种变体,因为首选多态性

在任何一种情况下,这两种方法都返回
NSMutableArray
的实例,唯一的区别是第一种方法对调用方隐藏了该事实。换句话说,第一种变体并不比第二种更安全。它本质上是使用多态性来告诉调用者任何类型的
NSArray
都可能被返回。如果您在代码中需要这种灵活性,它肯定有它的优点。(例如,如果有一天,出于任何原因,您需要返回一个自定义的
NSArray
子类,那么您的代码将不会在该级别中断)

然而,您似乎更喜欢向调用者传达意图,也就是说,您实际上返回可变数组,这也是可以的。为了让每个人都开心(如果还有这样的事情……),我建议将第二种方法重命名为:

- (NSMutableArray *)mutableFooBar {
    NSMutableArray *fooArray = [NSMutableArray array];
    //populate fooArray
    return fooArray;
}
作为旁注,我认为以下是将现有不可变数组转换为可变数组的更有效的方法:

NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:fooArray];
(如果我在这个假设上错了,请纠正我)


我希望这能回答您的问题…

让一个方法返回一个像这样的可变实例看起来很可疑

作为调用者,您必须对原始方法签名提出疑问,并怀疑修改返回值是否真的安全。毕竟,类可能会无意中返回指向内部状态的指针

如果分析显示这个副本确实很昂贵,我通常会更改方法签名,以使其明显地表明其目的是可变的。也许是这样的:

- (void)populateFooBars:(NSMutableArray *)array;

这样很明显,结果的可变性是故意的。

仅在一个类中(或者更确切地说是一个协议及其实现)就有19个方法返回
nsset
。在另一个协议/类别中为5。另外还有7个。将这些方法加倍将使我的项目成为维护的噩梦。这些方法被设置为高度粒度/模块化。它们的结果如我在问题中所述,通常是并集/减法/相交的。他们中的任何人都不可能返回碰巧是ivar的NSSet。相反,它们返回在方法运行时按需整理的对象集。90%的用户在内部使用NSMutableSet。忘了提到我的问题的最初原因是性能和内存至关重要。(请参阅我对David V答案的更详细评论)虽然您的两个答案都完全有道理,但我仍然不确定我的情况是否是使用NSMutableSet合适的罕见情况。如果性能和内存对这个项目不是那么重要的话,我就不会为必须创建额外的可变拷贝(我已经可变了,但已经公开了)NSSET而烦恼了。在我的项目可以使用的场景中,这些集合中可能有成千上万(甚至更多)的对象。克隆这些需要额外的时间和内存。(参见我对octy答案的评论)你的答案可能是其中一个合适的例子——我不知道。只要您认识到,通过公开可变内容,您就是在强迫任何实现以可接受可变内容的方式工作,并接受您可以继续并使其可变。我已经过多地记录了我的代码(尤其是对于那些可变返回值)。我的类的任何方法都不会返回(或将永远不会返回)任何表示内部状态的NSMutableSet。如果愿意,这是一个内部框架约定。所讨论的方法大多返回经过整理的核心数据关系。仅一个类就有19个这样的方法。另外还有19个以
-(voi)开头的方法