2008-08-28 2 views
15

Я знаю, что если у вас есть цикл, который изменяет количество элементов в цикле, использование NSEnumerator в наборе - лучший способ убедиться, что ваш код взорван, однако я бы как понять компромисс производительности между классом NSEnumerator и только старой школой для петлиПроизводительность NSEnumerator против цикла в Cocoa

ответ

26

Используя новый синтаксис for (... in ...) в Objective-C 2.0, как правило, самый быстрый способ перебора коллекции, поскольку он может поддерживать буфер в стеке и получать в него партии предметов.

Использование NSEnumerator, как правило, самый медленный путь, поскольку он часто копирует повторяющуюся сборку; для неизменяемых коллекций это может быть дешево (эквивалентно -retain), но для изменчивых коллекций он может создать неизменяемую копию.

Выполнение собственной итерации - например, с использованием -[NSArray objectAtIndex:] - обычно будет находиться где-то посередине, потому что, в то время как у вас не будет потенциального скопирования накладных расходов, вы также не будете получать партии объектов из базовой коллекции.

(PS - Этот вопрос должен быть помечен, как Objective-C, а не C, так как NSEnumerator класс какао и новый синтаксис for (... in ...) специфичен для Objective-C.)

2

Они очень похожи. С Objective-C 2.0 в большинстве перечислений теперь по умолчанию используется NSFastEnumeration, который создает буфер адресов для каждого объекта в коллекции, который он может доставить. Единственный шаг, который вы сохраняете в классическом цикле, - это не необходимость называть objectAtIndex:i каждый раз внутри цикла. Внутренности коллекции, которую вы перечисляете, реализуют быстрое перечисление без вызова objectAtIndex:i method.

Буфер является частью причины, по которой вы не можете мутировать коллекцию при перечислении, адрес объектов изменится, и созданный буфер больше не будет соответствовать.

В качестве бонуса формат в 2.0 выглядит так хорошо, как классический для цикла:

for (Type newVariable in expression) { 
    stmts 
} 

Прочитайте следующую documentaion углубиться: NSFastEnumeration Protocol Reference

+0

@Jeff Atwood, что ссылка не работает для меня. Вместо этого я просто установил Xcode 4. Я искал «NSFastEnumeration» в документации Xcode и API Reference, чтобы найти ссылку на NSFastEnumeration Protocol. – ma11hew28 2011-04-17 03:22:48

+0

@matt в будущем нажмите «отредактировать» и сделайте сообщение лучше для наших попутчиков. Я не занимаюсь разработкой iOS .. :) – 2011-04-17 03:32:35

5

После выполнения теста несколько раз, результат почти такой же. Каждый блок измерения выполняется 10 раз подряд.

В результате в моем случае от самой быстрой до медленной:

  1. for..in (testPerformanceExample3) (0,006 сек)
  2. Хотя (testPerformanceExample4) (0,026 сек)
  3. Для (;;) (testPerformanceExample1) (0.027 сек)
  4. блок Перечисление (testPerformanceExample2) (0,067 сек)

для и в то время цикла почти то же самое.

comparation between iterations

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 "About Testing with Xcode"

Смежные вопросы