Domanda

So che se hai un ciclo che modifica il conteggio degli elementi nel ciclo, utilizzare NSEnumerator su un set è il modo migliore per assicurarti che il tuo codice esploda, tuttavia mi piacerebbe capire i compromessi prestazionali tra la classe NSEnumerator e solo una vecchia scuola per il loop

È stato utile?

Soluzione

Usando il nuovo for (... in ...) la sintassi in Objective-C 2.0 è generalmente il modo più veloce per eseguire l'iterazione su una raccolta perché può mantenere un buffer nello stack e inserirvi batch di elementi.

Utilizzando NSEnumerator è generalmente il modo più lento perché spesso copia la raccolta in fase di iterazione;per le raccolte immutabili questo può essere economico (equivalente a -retain) ma per le raccolte mutabili può causare la creazione di una copia immutabile.

Eseguire la propria iterazione, ad esempio utilizzando -[NSArray objectAtIndex:] - generalmente si colloca nel mezzo perché, sebbene non avrai il potenziale sovraccarico di copia, non otterrai batch di oggetti dalla raccolta sottostante.

(PS: questa domanda dovrebbe essere contrassegnata come Objective-C, non C, poiché NSEnumerator è una classe Cocoa e la nuova for (... in ...) la sintassi è specifica di Objective-C.)

Altri suggerimenti

Dopo aver eseguito il test più volte, il risultato è quasi lo stesso.Ogni blocco di misure viene eseguito 10 volte consecutivamente.

Il risultato nel mio caso dal più veloce al più lento:

  1. Per...in (testPrestazioniEsempio3) (0,006 secondi)
  2. Mentre (testPrestazioniEsempio4) (0,026 secondi)
  3. Per(;;) (testPrestazioniEsempio1) (0,027 secondi)
  4. Blocco di enumerazione (testPrestazioniEsempio2) (0,067 secondi)

Il ciclo for e while è quasi lo stesso.

comparation between iterations

IL tmp è un NSArray che contiene 1 milione di oggetti da 0 a 999999.

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

L'intero codice:

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

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

Per maggiori informazioni visita: Mele "Informazioni sui test con Xcode"

Sono molto simili.Con Objective-C 2.0 la maggior parte delle enumerazioni ora vengono impostate automaticamente su NSFastEnumeration che crea un buffer degli indirizzi di ciascun oggetto nella raccolta che può quindi consegnare.L'unico passaggio che salvi nel classico ciclo for è non dover chiamare objectAtIndex:i ogni volta all'interno del loop.Gli interni della raccolta che stai enumerando implementano l'enumerazione rapida senza chiamate objectAtIndex:i method.

Il buffer è uno dei motivi per cui non è possibile modificare una raccolta durante l'enumerazione, l'indirizzo degli oggetti cambierà e il buffer creato non corrisponderà più.

Come bonus, il formato 2.0 sembra carino quanto il classico ciclo for:

for ( Type newVariable in expression ) { 
    stmts 
}

Leggi la seguente documentazione per approfondire:Riferimento al protocollo NSFastEnumeration

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top