2010-10-07 13 views
11

Dalla sperimentazione sembra che l'espressione della collezione venga valutata solo una volta. Considerate questo esempio:Obiettivo c "per ciascuna" (enumerazione rapida) - valutazione della raccolta?

static NSArray *a; 

- (NSArray *)fcn 
{ 
    if (a == nil) 
     a = [NSArray arrayWithObjects:@"one", @"two", @"three", nil]; 
    NSLog(@"called"); 
    return a; 
} 

... 

for (NSString *s in [self fcn]) 
    NSLog(@"%@", s); 

Il risultato è:

2010-10-07 07:37:31.419 WidePhotoViewer Lite[23694:207] called 
2010-10-07 07:37:31.420 WidePhotoViewer Lite[23694:207] one 
2010-10-07 07:37:31.425 WidePhotoViewer Lite[23694:207] two 
2010-10-07 07:37:31.425 WidePhotoViewer Lite[23694:207] three 

che indica che [sé fcn] viene chiamato solo una volta.

Qualcuno può confermare che questo è il comportamento specificato (rispetto al solo osservato)?

Quello che ho in mente è fare qualcosa di simile:

for (UIView *v in [innerView subviews]) { 

invece di questo:

NSArray *vs = [innerView subviews]; 
for (UIView *v in vs) { 

Pensieri?

+0

Grazie a quelli, esp. Shmurk, che ha cercato di rispondere ... questo fa davvero luce sull'argomento. (Il controllo di un'implementazione per chiarire una specifica è pericoloso. Comunque, l'avevo già fatto nel preparare la domanda.) –

risposta

13

Questo tipo di ciclo for è chiamato "enumerazione veloce" (guarda l'oggetto NSFastEnumeration). La documentazione di Apple afferma che in "for obj in expression", l'espressione produce un oggetto conforme al protocollo NSFastEnumeration, quindi suppongo che sia il comportamento corretto: la funzione viene chiamata una volta, un iteratore viene creato una volta e utilizzato nel ciclo.

0

Questo è parte del comportamento dell'enumerazione veloce. Per una conoscenza approfondita dell'implementazione dell'enumerazione veloce consulta questo post sul blog di NSBlog: Implementing Fast Enumeration.

3

Il buon senso impone che sia così. Ma dal momento che non è indicato direttamente nella enumerazione documentazione veloce, perché non si dispone di uno sguardo al protocollo stesso:

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSFastEnumeration_protocol/Reference/NSFastEnumeration.html

Questo protocollo non fornisce metodi come nextObject, o objectAtIndex, o qualcosa di simile questo, ma richiede invece un array C di oggetti, su cui viene poi iterato.

Sebbene vi siano indicazioni forti, nessun documento garantisce che l'espressione venga valutata solo una volta.

7

In pratica, collection viene valutato solo una volta, è possibile controllare la fonte di clang, per esempio. Quando la documentazione non dice le cose abbastanza precise, è necessario fidarsi dell'implementazione.

Sì, penso che Apple dovrebbe chiarire la documentazione. Si prega di presentare un bug, Marc!

Un modo pedante per ottenere questo è leggere il margine della documentazione ufficiale, che può essere trovato here. Si dice che

l'enumeratore ha una protezione di mutazione in modo che se si tenta di modificare la raccolta durante l'enumerazione, viene sollevata un'eccezione. Poiché la mutazione dell'oggetto durante l'iterazione è vietata, è possibile eseguire contemporaneamente più enumerazioni.

così, la raccolta su cui si esegue l'iterazione non può comunque cambiare.Esso non dice se si valuta collection in

for(id obj in collection) { ... } 

una o due volte, l'oggetto risultante non può cambiare.

+0

+1 solo per suggerire un bug-archiviare! – Wevah

Problemi correlati