我知道,如果您有一个循环来修改循环中项目的计数,则在集合上使用NSEnumerator是确保代码爆炸的最佳方法,但是我想了解NSEnumerator类之间的性能折衷 还有一所老学校
通常,在Objective-C 2.0中使用新的for (... in ...)语法是对集合进行迭代的最快方法,因为它可以在堆栈上维护一个缓冲区并将大量项目放入其中。
使用NSEnumerator通常是最慢的方法,因为它通常会复制要迭代的集合。对于不可变的集合,这可能很便宜(相当于-retain),但是对于可变的集合,这可能会导致创建不可变的副本。
进行自己的迭代(例如,使用-[NSArray objectAtIndex:])通常会介于两者之间,因为虽然您没有潜在的复制开销,但是您也不会从基础集合中获取一批对象。
(PS-此问题应标记为Objective-C,而不是C,因为NSEnumerator是Cocoa类,并且新的for (... in ...)语法特定于Objective-C。)
多次运行测试后,结果几乎相同。每个测量块连续运行10次。
在我的情况下,结果从最快到最慢:
For..in(testPerformanceExample3)(0.006秒)
While(testPerformanceExample4)(0.026秒)
For(;;)(testPerformanceExample1)(0.027秒)
枚举块(testPerformanceExample2)(0.067秒)
for和while循环几乎相同。
tmp是NSArray,其中包含1百万个对象,范围从0到999999。
1 2 3 4 5 6 7 8 9
| - (NSArray *)createArray
{
self.tmpArray = [NSMutableArray array];
for (int i = 0; i < 1000000; i++)
{
[self.tmpArray addObject:@(i)];
}
return self.tmpArray;
} |
整个代码:
ViewController.h
1 2 3 4 5 6 7 8
| #import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (strong, nonatomic) NSMutableArray *tmpArray;
- (NSArray *)createArray;
@end |
ViewController.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #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循环一样好:
1 2 3
| for ( Type newVariable in expression ) {
stmts
} |
阅读以下文档以更深入了解:
NSFastEnumeration协议参考