我有以下担忧。我有一段代码非常关心性能(说实话,我正在尝试使其尽可能优化)。
我有这样的东西:
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];
}
上述变化在绩效方面是否有意义?
答案 0 :(得分:1)
NSArray
支持写时复制。来自Foundation Release Notes for macOS 10.13 and iOS 11:
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];
}
复制导致两个对象共享后备存储。通过在更改array
之前清除marray
,应释放原件,只保留其中一个。然后,这些变异不需要复制,因为不再共享。
此外,按照该WWDC视频中的建议,当您有一种方法可以创建一个在设置时可变的数组,但又想返回不可变的数组时,可以并且应该返回一个副本,而不仅仅是直接指针:
- (NSArray *)getArray {
NSMutableArray *array = [NSMutableArray new];
// do some stuff here
return [array copy];
}
那更安全而且仍然便宜。