ios - 制作非可变对象的可变副本的首选方法?

标签 ios foundation

有 2 个选择(可能更多)。以 NSSet 为例:

NSMutableSet * mutableSet = [ NSMutableSet setWithSet:nonMutableSet ] ;

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

这两种实现有什么区别吗?一个“更有效率”吗? (其他例子是 NSArray/NSMutableArray 和 NSDictionary/NSMutableDictionary

最佳答案

基准测试的乐趣! :)

#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: 比 -mutableCopy 慢 ~3 倍(有人想在 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 在 callBacks 参数中带一个 CFSetHashCallBack;因此,两个 CFSets of CFNumbers 可以指定不同的哈希例程。 Foundation 的 NSSet 在底层使用 CFSet,并且有一个调用 -[NSObject hash] 的 CFSetHashCallBack 函数。 (虽然我猜想 Apple 可以优化这种情况并避免在两个集合具有相同的哈希回调时重新哈希)。

请注意,此基准测试仅适用于(NSNumbers 的)NSSet,其他集合类可能具有不同的性能特征。

关于ios - 制作非可变对象的可变副本的首选方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8985341/

相关文章:

ios - 如何本地化静态 UIApplicationShortcutItems?

ios - 为什么 initWithScheme 初始化的 NSURL 中有尾部斜杠...?

ios - 此处使用 '!' 已弃用,将在未来版本中删除 - swift 4.2

objective-c - 在 iOS 上,有没有更快的方法来获取 mainBundle 资源的 URL?

swift - 日期间隔格式化程序 : string of format "m:ss"

objective-c - 苹果私有(private)头文件中给出Underscore的原因是什么

ios - 如何在Swift 3中解析JSON数组

ios - Swift:与 DispatchGroup 的死锁

objective-c - NSMutableArray 背后的数据结构是什么?

multithreading - NSIndexPath 线程安全吗?