【问题标题】:NSArray's mutableCopy - performance concernsNSArray 的 mutableCopy - 性能问题
【发布时间】:2019-02-07 21:50:12
【问题描述】:

我有以下担忧。我有一段代码我非常关心性能(老实说,我正在努力使其尽可能优化)。

我有这样的事情:

NSArray *array = [someInstance getArray];
if (something) {
   NSMutableArray *marray = [array mutableCopy];
   [marray removeObject:someObject];
   [marray insertObject:someObject atIndex:0];

   array = marray;
}

目标是将someObject 移动到数组的开头——非常简单。然而,重点在别处。方法[someInstance getArray]返回NSArray *,但在内部它也使用NSMutableArray

- (NSArray *)getArray {
    NSMutableArray *array = [NSMutableArray new];
    // do some stuff here
    return array;
}

我试图让我的所有接口都返回不可变集合。但在上述情况下,我正在考虑从该规则中创建一个例外,因为我非常关心这段代码的性能。所以我可以把getArray方法改成如下:

- (NSMutableArray *)getArray {
    NSMutableArray *array = [NSMutableArray new];
    // do some stuff here
    return array;
}

然后把我的超高效代码改成如下:

NSMutableArray *array = [someInstance getArray];
if (something) {
   [array removeObject:someObject];
   [array insertObject:someObject atIndex:0];
}

上述更改在性能方面是否有意义?

【问题讨论】:

  • 你告诉我们。使用 Instruments 并对其进行测试。
  • 如果 Instruments 没有挂,我不会问 :)
  • 您在“优化”却无法衡量?不要那样做。没有什么好事。
  • 任何人都可以回答而不是问我为什么要问?老实说,我不想写一个关于我现在面临的 Instruments 问题的完整故事。我已经用 Instruments 完成了大部分工作,但现在它们不起作用(不知道为什么),这是我最后一个不明显的担忧。所以这就是我问的原因。
  • 我对您在使用 Instruments 时遇到的问题表示同情。我的意思是,假设您做出了我建议(或其他人)的更改。你怎么知道它是否有所改善?

标签: objective-c performance nsmutablearray nsarray


【解决方案1】:

NSArray 支持写时复制。来自Foundation Release Notes for macOS 10.13 and iOS 11

Collection Copy-on-Write

NSArray、NSDictionary 和 NSSet 现在实现了“写时复制”(CoW), 这意味着可变实例的副本通常不会是完整的 复制,但便宜得多,O(1) 操作。仅完成完整副本 当任一对象(原件或副本)发生变异时 下线。

请参阅WWDC 2017 session 244 “Efficient Interactions with Frameworks” 了解更多信息。

这意味着复制数组很便宜。但是,在原始版本仍然存在时对其进行修改可能会很昂贵。

所以,你可以这样做:

if (something) {
   NSMutableArray *marray = [array mutableCopy];
   array = nil;
   [marray removeObject:someObject];
   [marray insertObject:someObject atIndex:0];
   array = [marray copy];
}

复制导致两个对象共享一个后备存储。通过在改变marray 之前清除array,应该释放原始文件,只留下一个。然后,突变不需要复制它,因为它不再共享。

此外,正如该 WWDC 视频中所建议的那样,如果您有一个方法可以创建一个在设置时可变的数组,但您希望返回为不可变的,那么您可以而且应该返回一个副本而不是直接返回指针:

- (NSArray *)getArray {
    NSMutableArray *array = [NSMutableArray new];
    // do some stuff here
    return [array copy];
}

这样更安全,而且仍然便宜。

【讨论】:

  • 谢谢!最后建设性的答案:) 我不知道它是如何工作的。
  • 只是好奇:为什么在预期不可变的地方返回可变数组的副本更安全?如果视频中有解释,请忽略我。
  • 好吧,我想像-getArray 这样的方法并不安全,它正在创建一个新的可变数组并在它返回后忘记它。在将不可变类型指针返回到可能在其他地方引用的可变集合的方法的一般情况下,它更安全。
  • 这是有道理的。这就是为什么在我的特殊情况下我没有看到任何安全的好处。无论如何,感谢@ken-thomases 的解释!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-01
  • 1970-01-01
  • 2012-06-02
  • 2014-02-24
  • 2023-03-08
  • 2012-08-22
  • 2013-02-25
相关资源
最近更新 更多