Я знаю, что если у вас есть цикл, который изменяет количество элементов в цикле, использование NSEnumerator в наборе — лучший способ убедиться, что ваш код взрывается, однако я хотел бы понять компромиссы производительности между классом NSEnumerator. и просто старая школа цикла
Сравнение производительности NSEnumerator и цикла for в Cocoa
Ответы (3)
Использование нового синтаксиса for (... in ...)
в Objective-C 2.0, как правило, является самым быстрым способом перебора коллекции, поскольку он может поддерживать буфер в стеке и получать в него пакеты элементов.
Использование NSEnumerator
, как правило, является самым медленным способом, поскольку оно часто копирует итерируемую коллекцию; для неизменяемых коллекций это может быть дешево (эквивалентно -retain
), но для изменяемых коллекций это может привести к созданию неизменяемой копии.
Выполнение вашей собственной итерации — например, с использованием -[NSArray objectAtIndex:]
— обычно находится где-то посередине, потому что, хотя у вас не будет потенциальных накладных расходов на копирование, вы также не будете получать пакеты объектов из базовой коллекции.
(PS — этот вопрос должен быть помечен как Objective-C, а не C, поскольку NSEnumerator
— это класс Cocoa, а новый синтаксис for (... in ...)
специфичен для Objective-C.)
После запуска теста несколько раз результат практически одинаков. Каждый блок измерений выполняется 10 раз подряд.
Результат в моем случае от самого быстрого к самому медленному:
- For..in (testPerformanceExample3) (0,006 с)
- Пока (testPerformanceExample4) (0,026 с)
- For(;;) (testPerformanceExample1) (0,027 с)
- Блок перечисления (testPerformanceExample2) (0,067 с)
Циклы for и while почти одинаковы.
tmp
— это NSArray
, который содержит 1 миллион объектов от 0 до 999999.
- (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
#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
Для получения дополнительной информации посетите: Apples "О тестировании с помощью Xcode"
Они очень похожи. В Objective-C 2.0 для большинства перечислений теперь по умолчанию используется значение NSFastEnumeration
, которое создает буфер адресов для каждого объекта в коллекции, который затем может быть доставлен. Один шаг, который вы экономите по сравнению с классическим циклом for, заключается в том, что вам не нужно вызывать objectAtIndex:i
каждый раз внутри цикла. Внутренности перечисляемой вами коллекции реализуют быстрое перечисление без вызова objectAtIndex:i method
.
Буфер является одной из причин того, что вы не можете изменить коллекцию во время перечисления, адреса объектов изменятся, и созданный буфер больше не будет соответствовать.
В качестве бонуса формат в версии 2.0 выглядит так же красиво, как и классический цикл for:
for ( Type newVariable in expression ) {
stmts
}
Прочтите следующую документацию, чтобы узнать больше: Справочник по протоколу NSFastEnumeration< /а>
NSFastEnumeration
в документации Xcode и справочнике API, чтобы найти справочник протокола NSFastEnumeration.
- person ma11hew28; 17.04.2011