NSArray 的 mutableCopy - 性能问题

NSArray's mutableCopy - performance concerns

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

我有这样的东西:

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

   array = marray;
}

目标是将 someObject 移动到数组的开头 - 非常简单。然而,重点在别处。方法 [someInstance getArray] returns 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];
}

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

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

写时复制集合

NSArray, NSDictionary, and NSSet now implement “copy on write” (CoW), which means that a copy of a mutable instance will often not be a full copy, but a much cheaper, O(1) operation. A full copy is done only when either one of the objects (the original or the copy) is mutated down the line.

Please see WWDC 2017 session 244 “Efficient Interactions with Frameworks” for more info on this.

这意味着复制数组很便宜。但是,在原件还在的时候修改它可能会很昂贵。

所以,你可以这样做:

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

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

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

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

这样更安全而且便宜。