I know that if you have a loop that modifies the count of the items in the loop, using the NSEnumerator on a set is the best way to make sure your code blows up, however I would like to understand the performance tradeoffs between the NSEnumerator class and just an old school for loop
Using the new for (... in ...)
syntax in Objective-C 2.0 is generally the fastest way to iterate over a collection because it can maintain a buffer on the stack and get batches of items into it.
Using NSEnumerator
is generally the slowest way because it often copies the collection being iterated; for immutable collections this can be cheap (equivalent to -retain
) but for mutable collections it can cause an immutable copy to be created.
Doing your own iteration — for example, using -[NSArray objectAtIndex:]
— will generally fall somewhere in between because while you won't have the potential copying overhead, you also won't be getting batches of objects from the underlying collection.
(PS - This question should be tagged as Objective-C, not C, since NSEnumerator
is a Cocoa class and the new for (... in ...)
syntax is specific to Objective-C.)
After running the test several times, the result is almost the same. Each measure block runs 10 times consecutively.
The result in my case from the fastest to the slowest:
The for and while loop is almost the same.
The tmp
is an NSArray
which contains 1 million objects from 0 to 999999.
- (NSArray *)createArray
{
self.tmpArray = [NSMutableArray array];
for (int i = 0; i < 1000000; i++)
{
[self.tmpArray addObject:@(i)];
}
return self.tmpArray;
}
The whole code:
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
#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
For more information visit: Apples "About Testing with Xcode"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With