2011-10-13 22 views
6

Si consideri il seguente frammento di codice:Blocchi, loops e le variabili locali

for(/* some condition */) { 
    int x = rand(); 
    [array addObject:^(){ 
     NSLog(@"%d", x); 
    }] 
} 

for(void (^block)() in array) { 
    block(); 
} 

Ora ci si aspetterebbe questo frammento di codice per stampare tutti i valori assegnati a x in quanto per ciclo; tuttavia sembra che tutti i blocchi condividano la stessa variabile "x" (presumibilmente l'ultima).

Qualche idea sul perché sia ​​così e su come è possibile correggere il codice in modo che ogni blocco contenga la variabile 'x' come era nel momento in cui è stato definito il blocco?

+0

Sto ancora imparando i blocchi da solo, ma una cosa strana mi viene in mente qui. Quando si esegue addObject :, l'array per impostazione predefinita conserva l'oggetto blocco. Tuttavia, gli oggetti di blocco vengono messi in pila quando vengono dichiarati, quindi sembra che qui sarebbero immediatamente fuori portata. Block_Copy sposta il blocco sull'heap che sembra la cosa giusta da fare. –

risposta

7

La documentazione specificatamente says not to do this. Il motivo è che i blocchi vengono assegnati allo stack nello stack, il che significa che possono uscire dall'ambito. Per lo stesso motivo per cui non è possibile accedere alla variabileal di fuori del primo ciclo for, non si dovrebbe utilizzare questo blocco. x è uscito dall'ambito, insieme al blocco stesso e potrebbe contenere qualsiasi valore.

Per aggirare il problema, si può prendere una copia del blocco in questo modo:

for(/* some condition */) { 
    int x = rand(); 
    void(^logBlock)() = ^() { NSLog(@"%d", x); } 
    [array addObject:[[logBlock copy] autorelease]]; 
} 

Questo sposta il blocco sul mucchio, e dovrebbe risolvere il problema.