优化NSNumber numberWithInt:

时间:2012-03-27 01:08:46

标签: iphone objective-c performance nsnumber

我正在分析iPhone应用程序,我发现了一个奇怪的模式。在一段经常调用的代码块中......

    [item setQuadrant:[NSNumber numberWithInt:a]];
    [item setIndex:[NSNumber numberWithInt:b]];
    [item setTimestamp:[NSNumber numberWithInt:c]];
    [item setState:[NSNumber numberWithInt:d]];
    [item setCompletionPercentage:[NSNumber numberWithInt:e]];
    [item setId_:[NSNumber numberWithInt:f]];

...对[NSNumber numberWithInt:]的第一次调用花费了过多的时间,大约是其余调用的10-15倍。我已经验证了如果我改变线条的结果是一致的(第一行总是慢的,按相同的比例)。是否有一些我不知道的事情?

也许这是因为这个块在try / catch中?

2 个答案:

答案 0 :(得分:1)

如果我不得不猜测,NSNumber会在它的+load实现中执行一些代码,这会减慢对该类的初始调用。另请注意,NSNumber会缓存它的返回值,因此将来调用具有相同值的+numberWithInt:比以前更快,这可能是问题的一部分。

答案 1 :(得分:-1)

也许第一个值要大得多?除了CoreFoundation的CFNumber缓存之外,“新”运行时使用标记指针,允许24位范围内的整数直接编码到指针中 - 然后运行时通过查看最后一位(并且它的位置)来确定它是标记指针CFNumber通过查看最后一位之前的3位和目标数字大小 - 8,16,32,64位 - 使用之前的下4位)。
在32位系统(当前的iPhone)上,这意味着对于(“小”)负32位数或大的正数,CoreFoundation将分配一个对象。对于其他所有内容,它使用以下更快的表达式:

    case kCFNumberSInt32Type: {
            int32_t value = *(int32_t *)valuePtr; // this loads the actual numerical value passed to CFNumberCreate()
#if !__LP64__
            // We don't bother allowing the min 24-bit integer -2^23 to also be fast-pathed;
            // tell anybody that complains about that to go ... hang.
            int32_t limit = (1L << 23);
            if (value <= -limit || limit <= value) break;
#endif
            uintptr_t ptr_val = ((uintptr_t)((intptr_t)value << 8) | (2 << 6) | kCFTaggedObjectID_Integer);
            return (CFNumberRef)ptr_val;
        }

(请注意,!__LP64__适用于32位系统)

取自:http://www.opensource.apple.com/source/CF/CF-744.12/CFNumber.c

此外,还有一种缓存机制可以防止多次重新创建数字,只需在同一源文件中搜索“__CFNumberCache”。