在从方法返回之前将可变 NSObject 转换为不可变 NSObject 是否有必要或值得?

Is it necessary or worthwhile to convert mutable NSObjects to immutable ones before returning from methods?

假设您有一个 return NSDictionary 的方法。要构建字典,您可能需要创建一个 NSMutableDictionary。 return 字典的不可变副本而不只是 return 可变字典是否有任何需要或优势?

例如

- (NSDictionary *)doSomethingAndReturnADictionary {
    NSMutableDictionary * dic = [NSMutableDictionary new];
    // fill in dic
    return dic;
}

还是执行以下操作更好:

- (NSDictionary *)doSomethingAndReturnADictionary {
    NSMutableDictionary * dic = [NSMutableDictionary new];
    // fill in dic
    return [NSDictionary dictionaryWithDictionary:dic];
}

我认为复制字典,尤其是大字典,是一种资源浪费。我假设 NSMutableDictionary 占用更多内存,但我怀疑两者之间存在重大差异。该方法可以 return 和 NSMutableDictionary,但是如果字典不打算在 returning 之后被修改,何必呢? returned 字典是 NSMutableDictionary,但编译器会将其显示为 NSDictionary

同样的问题适用于NSArrayNSString等。我没能找到类似的问题。

有什么最佳做法/需要考虑的事项吗?

你是对的,这通常是一种资源浪费,而且没有必要。可变字典仍然是字典,任何对函数的 return 值感兴趣的人都知道将其视为普通字典。我们可以为此感谢继承。

Apple 似乎遵循了同样的建议: [NSThread callStackSymbols] 的 return 值是一个 NSArray,但如果你在运行时检查它,你会发现它是 NSMutableArray

的一个实例

IMO,如果期望不可变,这是 return 不可变对象的一个​​好习惯。

考虑一下:

NSString *stringExpectedToBeImmutable = [NSMutableString stringWithString:@"My immutable string."];

[((NSMutableString *) stringExpectedToBeImmutable) appendString:@" Really?"];

NSLog(@"%@", stringExpectedToBeImmutable);

有人可能期望传递给方法的 NSString 是不可变的,并基于此假设进行一些计算,然后在计算过程中字符串会发生变化。当计算开始时,字符串是 20 个字符长,突然变成 28 个字符。

这也是为什么 NSString 类型的属性应该声明为 copy.

的原因

这当然是一些极端情况,但很好地说明了问题。

您可以调用 [dic copy] 而不是 [NSDictionary dictionaryWithDictionary:dic]。我认为 copy 是获取可变对象的不可变副本的最有效方法。

总结:

  • 如果你说你是 returning 不可变对象,return 不可变
  • 如果某些方法或 API 需要不可变对象,则给它们不可变
  • 使用copy获取可变对象的不可变版本
  • 我不怕性能开销。过早的优化是邪恶的:)