每次调用count方法时,NSMutableArray是否实际计算项目?

时间:2013-01-31 23:45:11

标签: objective-c nsmutablearray performance

由于cocoa设计模式,count中的实例方法NSMutableArray的名称不明确;它可以返回一个保存的变量count,或者它可以在每次调用时计算数组中的项,并返回它(cocoa指示一个简单地返回变量foo的值的方法是foo,而非getFoo)。 每次调用NSMutableArray方法时,Objective C的count是否实际计算项目,还是返回预先计算的变量的值?如果这是Java,我看看源代码,但我找不到NSMutableArray的源代码。我查看了API,它说的只是:

  

返回当前数组中的对象数。

由于没有上下文,我无法判断这是否意味着它内部进行了任何计算。

2 个答案:

答案 0 :(得分:7)

正如您已经正确指出的那样,无法保证它会以某种方式运行。

但实际上,-[NSArray count]是一个固定时间操作。您可以通过创建一个小数组和一个大型数组并对获取计数所需的时间进行基准测试来自行确认。在这样的核心数组类上使用O(n)count方法会非常愚蠢。

答案 1 :(得分:5)

NSArray声明私有ivar _used,它似乎保留了数组的计数。使用object_getInstanceVariable(),您可以验证在具体子类__NSArrayM的情况下,此变量在添加和删除对象时递增和递减。

我使用以下程序(Mac OS X Foundation命令行工具)来验证:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {

        NSMutableArray *anArray = [NSMutableArray array];
        NSLog(@"anArray's concrete class is %@", [anArray class]);
        UInt64 used = 0;
        for (NSString *toAdd in @[@"o", @"m", @"g"]) {
            object_getInstanceVariable(anArray, "_used", (void **)&used);
            NSLog(@"array = %@, used = %lld", anArray, used);
            [anArray addObject:toAdd];
        }
        for (NSString *toRemove in [anArray copy]) {
            object_getInstanceVariable(anArray, "_used", (void **)&used);
            NSLog(@"array = %@, used = %lld", anArray, used);
            [anArray removeObject:toRemove];
        }
        object_getInstanceVariable(anArray, "_used", (void **)&used);
        NSLog(@"array = %@, used = %lld", anArray, used);
    }
    return 0;
}

该程序产生以下输出:

2013-01-31 17:40:15.376 Array[10173:303] anArray's concrete class is __NSArrayM
2013-01-31 17:40:15.378 Array[10173:303] array = (
), used = 0
2013-01-31 17:40:15.378 Array[10173:303] array = (
    o
), used = 1
2013-01-31 17:40:15.379 Array[10173:303] array = (
    o,
    m
), used = 2
2013-01-31 17:40:15.379 Array[10173:303] array = (
    o,
    m,
    g
), used = 3
2013-01-31 17:40:15.380 Array[10173:303] array = (
    m,
    g
), used = 2
2013-01-31 17:40:15.380 Array[10173:303] array = (
    g
), used = 1
2013-01-31 17:40:15.380 Array[10173:303] array = (
), used = 0