Cocoa 中的 NSEnumerator 性能与 for 循环

NSEnumerator performance vs for loop in Cocoa

提问人:Heat Miser 提问时间:8/29/2008 最后编辑:The Archetypal PaulHeat Miser 更新时间:6/9/2015 访问量:7057

问:

我知道,如果您有一个修改循环中项计数的循环,那么在集合上使用 NSEnumerator 是确保您的代码爆炸的最佳方法,但是我想了解 NSEnumerator 类和老式 for 循环之间的性能权衡

Objective-C Cocoa Nsenumerator

评论


答:

2赞 RogueStrider 8/29/2008 #1

它们非常相似。在 Objective-C 2.0 中,大多数枚举现在默认为该枚举,该枚举会为集合中的每个对象创建一个地址缓冲区,然后它可以传递该缓冲区。在经典的 for 循环中保存的一个步骤是不必每次都在循环中调用。要枚举的集合的内部实现快速枚举,而无需调用 。NSFastEnumerationobjectAtIndex:iobjectAtIndex:i method

缓冲区是枚举时无法更改集合、对象地址将更改以及生成的缓冲区将不再匹配的部分原因。

作为奖励,2.0 中的格式看起来和经典的 for 循环一样好:

for ( Type newVariable in expression ) { 
    stmts 
}

阅读以下文档以更深入地了解:NSFastEnumeration 协议参考

评论

0赞 ma11hew28 4/17/2011
@Jeff阿特伍德,这个链接对我不起作用。相反,我刚刚安装了 Xcode 4。我在 Xcode 的文档和 API 参考中搜索以查找 NSFastEnumeration 协议参考。NSFastEnumeration
0赞 Jeff Atwood 4/17/2011
@matt将来点击“编辑”,为我们的旅行者提供更好的帖子。我不做任何iOS开发。:)
28赞 Chris Hanson 8/29/2008 #2

在 Objective-C 2.0 中使用新语法通常是遍历集合的最快方法,因为它可以在堆栈上维护缓冲区并将成批的项放入其中。for (... in ...)

使用通常是最慢的方式,因为它经常复制正在迭代的集合;对于不可变集合,这可能很便宜(相当于 ),但对于可变集合,它可能会导致创建不可变副本。NSEnumerator-retain

执行自己的迭代(例如,使用 )通常介于两者之间,因为虽然您不会有潜在的复制开销,但您也不会从基础集合中获取成批的对象。-[NSArray objectAtIndex:]

(PS - 这个问题应该标记为 Objective-C,而不是 C,因为这是一个 Cocoa 类,并且新语法特定于 Objective-C。NSEnumeratorfor (... in ...)

5赞 Zsivics Sanel 6/9/2015 #3

运行几次测试后,结果几乎相同。每个测量块连续运行 10 次。

在我的情况下,结果从最快到最慢:

  1. 为。。in (testPerformanceExample3) (0.006秒)
  2. While (testPerformanceExample4) (0.026 秒)
  3. for(;;)(testPerformanceExample1)(0.027秒)
  4. 枚举块 (testPerformanceExample2) (0.067 秒)

for 和 while 循环几乎相同。

comparation between iterations

它包含从 0 到 999999 的 100 万个对象。tmpNSArray

- (NSArray *)createArray
{
    self.tmpArray = [NSMutableArray array];
    for (int i = 0; i < 1000000; i++)
    {
        [self.tmpArray addObject:@(i)];
    }
    return self.tmpArray;
}

整个代码:

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@property (strong, nonatomic) NSMutableArray *tmpArray;
- (NSArray *)createArray;

@end

ViewController.m的

#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createArray];
}

- (NSArray *)createArray
{
    self.tmpArray = [NSMutableArray array];
    for (int i = 0; i < 1000000; i++)
    {
        [self.tmpArray addObject:@(i)];
    }
    return self.tmpArray;
}

@end

MyTestfile.m(我的测试文件.m)

#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>

#import "ViewController.h"

@interface TestCaseXcodeTests : XCTestCase
{
    ViewController *vc;
    NSArray *tmp;
}

@end

@implementation TestCaseXcodeTests

- (void)setUp {
    [super setUp];
    vc = [[ViewController alloc] init];
    tmp = vc.createArray;
}

- (void)testPerformanceExample1
{
    [self measureBlock:^{
        for (int i = 0; i < [tmp count]; i++)
        {
            [tmp objectAtIndex:i];
        }
    }];
}

- (void)testPerformanceExample2
{
    [self measureBlock:^{
        [tmp enumerateObjectsUsingBlock:^(NSNumber *obj, NSUInteger idx, BOOL *stop) {
           obj;
        }];
    }];
}

- (void)testPerformanceExample3
{
    [self measureBlock:^{
        for (NSNumber *num in tmp)
        {
            num;
        }
    }];
}

- (void)testPerformanceExample4
{
    [self measureBlock:^{
        int i = 0;
        while (i < [tmp count])
        {
            [tmp objectAtIndex:i];
            i++;
        }
    }];
}

@end

有关更多信息,请访问:Apple的“关于使用Xcode进行测试”

评论

1赞 Jesse Gumpo 1/28/2017
您的结论是正确的,但是 for(;;) 测试可以通过在每个循环后不调用 [tmp count] 来更快。
0赞 Zsivics Sanel 1/29/2017
是的,你是对的,在本例中,for(;;) 测试结果为 0.023,while 循环测试结果为 0.022