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

有帮助吗?

解决方案

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

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

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

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

其他提示

运行测试几次后,结果几乎是一样的。每个测量块连续运行 10 次。

在我的例子中,结果从最快到最慢:

  1. 为..在 (测试性能示例3) (0.006 秒)
  2. 尽管 (测试性能示例4) (0.026 秒)
  3. 为了(;;) (测试性能示例1) (0.027 秒)
  4. 枚举块 (测试性能示例2) (0.067 秒)

for 和 while 循环几乎相同。

comparation between iterations

tmp 是一个 NSArray 其中包含 100 万个从 0 到 999999 的对象。

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

整个代码:

视图控制器.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

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

@end

视图控制器.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

我的测试文件.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

欲了解更多信息,请访问: 苹果“关于使用 Xcode 进行测试”

他们非常相似。对于 Objective-C 2.0,大多数枚举现在默认为 NSFastEnumeration 它创建一个缓冲区,其中包含集合中每个对象的地址,然后可以传递该缓冲区。与经典的 for 循环相比,您节省的一步是不必调用 objectAtIndex:i 每次在循环内。您正在枚举的集合的内部实现快速枚举,无需调用 objectAtIndex:i method.

缓冲区是您在枚举时无法改变集合的部分原因,对象的地址将更改并且构建的缓冲区将不再匹配。

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

for ( Type newVariable in expression ) { 
    stmts 
}

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top