6

Capisco che il tipo di memoria __block sia necessario sulle variabili scalari affinché il blocco veda gli aggiornamenti, ma quando è necessario sugli oggetti? Credo che __weak debba essere usato quando si acquisisce un riferimento personale da utilizzare all'interno del blocco, ma non vedo quando sarebbe necessario utilizzare effettivamente il tipo di memoria __block per oggetti ordinari.Quando utilizzare la parola chiave __block sui riferimenti agli oggetti con ARC

+0

anche [quale sia la differenza tra il __weak e __block riferimento?] (http://stackoverflow.com/questions/11773342/what-the-difference-between-weak-and-block-reference) –

+0

Mi chiedo in particolare: quando il tipo di archiviazione '__block' può essere usato su riferimenti non scalari, non auto-oggetti quando si usa ARC? Se quegli altri link rispondono a questa domanda, mi sono perso. – chinabuffet

+0

@chinabuffet: non esiste alcuna differenza tra il modo in cui funziona per i tipi scalari e i tipi di puntatori oggetto. – newacct

risposta

15

__block è necessario per le variabili scalari se si desidera modificare il loro valore con il codice all'interno del blocco. Gli scalari acquisiti vengono visualizzati come const all'interno del blocco e, pertanto, non possono essere modificati. Se si ha un puntatore a un oggetto, si applica la stessa distinzione: il puntatore catturato stesso sarà un puntatore const e, pertanto, non può essere modificato, ma l'oggetto puntato può essere modificato dal codice all'interno del blocco. Se si desidera modificare l'oggetto puntato a, allora il puntatore stesso deve cambiare, e quindi il puntatore deve essere dichiarato con il tipo __block. Non è mai necessario dichiarare l'oggetto stesso come __block, ma solo il puntatore all'oggetto e solo se il puntatore deve essere modificato.

Se si dispone del modello mentale corretto, i blocchi non sono così confusi. È importante sapere che i blocchi vengono inizialmente allocati nello stack e quindi svaniscono quando l'ambito lessicale viene distrutto mentre viene eseguito lo snap frame dello stack. Se si desidera che il blocco si blocchi attorno alla durata dell'ambito lessicale in cui è stato creato il blocco, spostarlo nell'heap utilizzando Block_copy() o inviando un messaggio -copy. Quando un blocco viene copiato nell'heap, tutte le variabili acquisite const vanno avanti e tutti gli oggetti a cui queste variabili const puntano sono mantenuti. Quando il blocco viene rimosso dall'heap, vengono rilasciati tutti gli oggetti a cui sono state indirizzate le variabili const.

__block variabili "sotto la cappa" hanno uno strato aggiuntivo di riferimento indiretto che il compilatore usa (e che non vedi) incluso nel blocco, quindi quando il blocco viene copiato nell'heap, lo sono anche le variabili catturate __block e i puntatori invisibili vengono regolati in modo da puntare alla nuova posizione heap di queste variabili __block. Ciò significa che l'indirizzo di una variabile __block può cambiare, quindi fai attenzione se usi quell'indirizzo. Si può anche vedere che una variabile __block vive "al di fuori" del blocco in un certo senso, quindi queste variabili possono essere lette e modificate dal codice esterno al blocco.

Sono stato breve, ma si possono trovare spiegazioni migliori qui, elencati nella crescente complessità:

http://ios-blog.co.uk/tutorials/programming-with-blocks-an-overview/

http://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html

http://www.mikeash.com/pyblog/friday-qa-2011-06-03-objective-c-blocks-vs-c0x-lambdas-fight.html

+0

Quindi se il blocco viene passato come riferimento da qualche parte, qualsiasi cosa sta ricevendo quel blocco come parametro deve immediatamente copiare il blocco per poterlo usare in futuro? – chinabuffet

+0

Se il riferimento del blocco può sopravvivere all'ambito lessicale (frame dello stack) in cui è stato definito il blocco, è necessario copiarlo per spostare l'oggetto del blocco sull'heap. Penserei che sarebbe più sicuro fare la copia durante la creazione del blocco piuttosto che fare in modo che queste copie si trovino in luoghi lontani dalla creazione. – Fred

0

Sono utilizzati per variabili a livello di funzione. Questi sono mutabili all'interno del blocco (e dell'ambito che lo racchiude) e sono conservati se un blocco di riferimento viene copiato nell'heap. Le variabili locali all'ambito lessicale allegato dichiarate con il modificatore di memoria __block sono fornite per riferimento e quindi sono mutabili. Qualsiasi modifica si riflette nell'accluso ambito lessicale, inclusi eventuali altri blocchi definiti all'interno dello stesso ambito lessicale che li circonda.

__block le variabili vivono nella memoria condivisa tra l'ambito lessicale della variabile e tutti i blocchi e le copie di blocco dichiarati o creati nell'ambito della variabile lessicale della variabile. Pertanto, l'archiviazione sopravviverà alla distruzione del frame dello stack se tutte le copie dei blocchi dichiarati all'interno del frame sopravvivono oltre la fine del frame (ad esempio, essere accodati da qualche parte per l'esecuzione successiva). Quindi usali quando hai bisogno di modificare l'oggetto all'interno di un blocco o quando avrai bisogno dell'oggetto dopo la distruzione del frame dello stack.