2008-08-28 8 views
15

Ich weiß, dass, wenn Sie eine Schleife haben, die die Anzahl der Elemente in der Schleife ändert, die Verwendung des NSEnumerator auf einem Satz ist der beste Weg, um sicherzustellen, dass Ihr Code explodiert, aber ich würde gerne die Leistungsabsprachen zwischen der Klasse NSEnumerator und nur eine alte Schule für Schleife zu verstehenNSEnumerator Leistung vs for Schleife in Cocoa

Antwort

26

Mit der neuen for (... in ...) Syntax in Objective-C 2.0 ist im Allgemeinen der schnellste Weg, um über eine Sammlung zu iterieren, da sie einen Puffer auf dem Stapel verwalten und Stapel von Elementen darin aufnehmen kann.

Die Verwendung von NSEnumerator ist im Allgemeinen der langsamste Weg, da es oft die Sammlung kopiert, die iteriert wird; Für unveränderbare Sammlungen kann dies billig sein (entspricht -retain), aber bei veränderlichen Sammlungen kann es dazu führen, dass eine unveränderbare Kopie erstellt wird.

Eine eigene Iteration, z. B. -[NSArray objectAtIndex:], wird normalerweise irgendwo dazwischen liegen, da Sie zwar keinen potenziellen Kopieraufwand haben, aber keine Stapel von Objekten aus der zugrunde liegenden Sammlung erhalten.

(PS - Diese Frage sollte als Objective-C, C nicht markiert werden, da NSEnumerator eine Cocoa-Klasse und die neue for (... in ...) Syntax ist spezifisch für Objective-C.)

2

Sie sind sehr ähnlich. Bei Objective-C 2.0 werden die meisten Enumerationen jetzt standardmäßig auf NSFastEnumeration gesetzt, wodurch für jedes Objekt in der Sammlung ein Puffer der Adressen erstellt wird, den es dann liefern kann. Der einzige Schritt, den Sie über die klassische for-Schleife speichern, ist, dass Sie nicht jedes Mal innerhalb der Schleife objectAtIndex:i aufrufen müssen. Die Interna der Auflistung, die Sie auflisten, implementieren schnelle Aufzählung ohne Aufruf objectAtIndex:i method.

Der Puffer ist Teil des Grundes, dass Sie eine Auflistung nicht mutieren können, während Sie aufzählen, die Adresse der Objekte wird sich ändern und der Puffer, der erstellt wurde, stimmt nicht mehr überein.

Als Bonus das Format in 2.0 so schön wie die klassischen for-Schleife sieht:

for (Type newVariable in expression) { 
    stmts 
} 

Lesen Sie die folgende documentaion tiefer gehen: NSFastEnumeration Protocol Reference

+0

@ Jeff Atwood, dass Link für mich nicht funktioniert hat. Stattdessen habe ich Xcode 4 installiert. Ich suchte in der Dokumentation und API-Referenz von Xcode nach "NSFastEnumeration", um die NSFastEnumeration Protocol Reference zu finden. – ma11hew28

+0

@matt in der Zukunft klicken Sie auf "Bearbeiten" und machen den Beitrag besser für unsere Mitreisenden. Ich mache keine iOS-Entwicklung .. :) –

5

den Test mehrmals nach dem Ausführen, Das Ergebnis ist fast das Gleiche. Jeder Messblock wird 10 Mal hintereinander ausgeführt.

Das Ergebnis ist in meinem Fall vom schnellsten zum langsamsten:

  1. for..in (testPerformanceExample3) (0,006 sec)
  2. Während (testPerformanceExample4) (0,026 sec)
  3. Für (;;) (testPerformanceExample1) (0,027 Sek.)
  4. Enumeration Block (testPerformanceExample2) (0,067 sec)

Die FOR- und While-Schleife ist fast das gleiche.

comparation between iterations

Die tmp ist ein NSArray, die enthält 1 Million Objekte von 0 bis 999999.

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

Der gesamte 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 

Weitere Informationen finden Sie unter: Apples "About Testing with Xcode"

+1

Ihre Schlussfolgerung ist richtig, aber der ** for (;;) ** Test kann schneller sein, indem Sie nach jeder Schleife nicht ** [tmp count] ** aufrufen. –

+0

Ja, Sie haben Recht, in diesem Fall ist das ** für (;;) ** Testergebnis ** 0,023 ** und das Ergebnis für den ** während ** Loop Test ist ** 0,022 ** –