Предпочитаемый способ сделать изменчивую копию неизменяемого объекта? - PullRequest
5 голосов
/ 24 января 2012

Есть 2 варианта (возможно, больше).Используя NSSet в качестве примера:

NSMutableSet * mutableSet = [ NSMutableSet setWithSet:nonMutableSet ] ;

или

NSMutableSet * mutableSet = [ [ nonMutableSet mutableCopy ] autorelease ] ;

Есть ли разница между этими двумя реализациями?Один "более эффективен" вообще?(Другими примерами могут быть NSArray / NSMutableArray и NSDictionary / NSMutableDictionary

1 Ответ

7 голосов
/ 24 января 2012

эталон веселья! :)

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{ @autoreleasepool {
    NSMutableSet *masterSet = [NSMutableSet set];

    for (NSInteger i = 0; i < 100000; i++) {
        [masterSet addObject:[NSNumber numberWithInteger:i]];
    }

    clock_t start = clock();

    for (NSInteger i = 0; i < 100; i++) {
        @autoreleasepool {
            [NSMutableSet setWithSet:masterSet];
        }
    }

    NSLog(@"a: --- %lu", clock() - start);

    sleep(1);

    start = clock();

    for (NSInteger i = 0; i < 100; i++) {
        @autoreleasepool {
            [[masterSet mutableCopy] autorelease]; 
        }
    }

    NSLog(@"b: --- %lu", clock() - start);

    return 0;
} }

На моей машине (10.7) setWithSet: примерно в 3 раза медленнее, чем -mutableCopy (кто-то хочет попробовать на iOS 5? :))

Теперь вопрос: почему?

-mutableCopy проводит большую часть своего времени в CFBasicHashCreateCopy () (см. CFBasicHash.m ). Похоже, что это копирование блоков хэша напрямую, без перефразирования.

Running  Time   Self  Symbol Name
256.0ms  61.5%  0.0   -[NSObject mutableCopy]
256.0ms  61.5%  0.0     -[__NSCFSet mutableCopyWithZone:]
256.0ms  61.5%  0.0       CFSetCreateMutableCopy
255.0ms  61.2%  156.0       CFBasicHashCreateCopy
97.0ms   23.3%  44.0          __CFSetStandardRetainValue

-setWithSet перечисляет каждое значение набора, а затем добавляет его в новый набор. Из реализации CFBasicHashAddValue (снова в CFBasicHash.m ), похоже, что он перефразирует каждое значение в наборе.

Running    Time Self    Symbol Name
1605.0ms   86.0%    0.0     +[NSSet setWithSet:]
1605.0ms   86.0%    2.0       -[NSSet initWithSet:copyItems:]
1232.0ms   66.0%    68.0        -[__NSPlaceholderSet initWithObjects:count:]
1080.0ms   57.8%    299.0         CFBasicHashAddValue
324.0ms    17.3%    28.0        -[NSSet getObjects:count:]
272.0ms    14.5%    75.0          __CFBasicHashFastEnumeration

Эта перефразировка имеет смысл на уровне CFSet. CFSets принимает CFSetHashCallBack в параметре callBacks; таким образом, два набора CFSets номеров CFN могут иметь различную заданную процедуру хеширования. NSSet Фонда использует CFSet скрытно и имеет функцию CFSetHashCallBack, которая вызывает -[NSObject hash]. (Хотя я предполагаю, что Apple могла бы оптимизировать этот случай и избежать перефразирования, когда два набора имеют одинаковый обратный вызов хеша).

Обратите внимание, что этот тест предназначен только для NSSet (из NSNumbers), другие классы сбора могут иметь другие характеристики производительности.

...