Question

Je sais que si vous avez une boucle qui modifie le nombre d'éléments dans la boucle, utiliser NSEnumerator sur un ensemble est le meilleur moyen de vous assurer que votre code explose. Cependant, j'aimerais comprendre les compromis de performances entre la classe NSEnumerator. et juste une vieille école de boucle

Était-ce utile?

La solution

Utiliser le nouveau for (... in ...) La syntaxe en Objective-C 2.0 est généralement le moyen le plus rapide de parcourir une collection car elle peut maintenir un tampon sur la pile et y insérer des lots d'éléments.

En utilisant NSEnumerator est généralement le moyen le plus lent car il copie souvent la collection en cours d'itération ;pour les collections immuables, cela peut être bon marché (équivalent à -retain), mais pour les collections mutables, cela peut entraîner la création d'une copie immuable.

Faire votre propre itération - par exemple, en utilisant -[NSArray objectAtIndex:] - se situera généralement quelque part entre les deux, car même si vous n'aurez pas de surcharge potentielle de copie, vous n'obtiendrez pas non plus de lots d'objets de la collection sous-jacente.

(PS - Cette question devrait être étiquetée comme Objective-C, pas C, puisque NSEnumerator est une classe Cocoa et le nouveau for (... in ...) la syntaxe est spécifique à Objective-C.)

Autres conseils

Après avoir effectué le test plusieurs fois, le résultat est presque le même.Chaque bloc de mesure s'exécute 10 fois consécutivement.

Le résultat dans mon cas du plus rapide au plus lent :

  1. Pour..dans (testPerformanceExample3) (0,006 s)
  2. Alors que (testPerformanceExample4) (0,026 s)
  3. Pour(;;) (testPerformanceExample1) (0,027 s)
  4. Bloc d'énumération (testPerformanceExample2) (0,067 s)

Les boucles for et while sont presque les mêmes.

comparation between iterations

Le tmp est un NSArray qui contient 1 million d'objets de 0 à 999999.

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

Le code complet :

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

MonFichierTest.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

Pour plus d'informations, visitez: Apples "À propos des tests avec Xcode"

Ils sont très similaires.Avec Objective-C 2.0, la plupart des énumérations sont désormais par défaut NSFastEnumeration qui crée un tampon des adresses de chaque objet de la collection qu'il peut ensuite livrer.La seule étape que vous enregistrez sur la boucle for classique est de ne pas avoir à appeler objectAtIndex:i à chaque fois à l'intérieur de la boucle.Les éléments internes de la collection que vous énumérez implémentent une énumération rapide sans appel objectAtIndex:i method.

Le tampon fait partie de la raison pour laquelle vous ne pouvez pas muter une collection pendant que vous énumérez, l'adresse des objets changera et le tampon qui a été construit ne correspondra plus.

En bonus le format en 2.0 est aussi joli que le classique for loop :

for ( Type newVariable in expression ) { 
    stmts 
}

Lisez la documentation suivante pour approfondir :Référence du protocole NSFastEnumeration

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top