68

Sto leggendo la documentazione di Xcode, e qui è una cosa che mi lascia perplesso:Qual è la differenza tra un riferimento __weak e __block?

__block typeof(self) tmpSelf = self; 
[self methodThatTakesABlock:^ { 
    [tmpSelf doSomething]; 
}]; 

Di seguito è copiato dalla documentazione:

In un blocco forme un forte riferimento a variabili che cattura. Se si utilizza self all'interno di un blocco, il blocco costituisce un riferimento forte a self, quindi se self ha anche un forte riferimento al blocco (che in genere è ), si ottiene un ciclo di riferimento forte. Per evitare il ciclo, è necessario creare un riferimento debole (o __block) al sé al di fuori del blocco, come nell'esempio sopra.

Non capisco cosa significa "debole (o __block)"?

È

__block typeof(self) tmpSelf = self; 

e

__weak typeof(self) tmpSelf = self; 

esattamente lo stesso qui

ho trovato un altro pezzo nel documento:?

Nota: In un garbage collection ambiente, se si applica sia __weak e __block modificatori di una variabile, quindi il blocco non garantisce che sia mantenuto in vita.

Quindi, sono totalmente perplesso.

risposta

99

Dalla documentazione circa __block

variabili __block vivono nella memoria che è condiviso tra l'ambito lessicale della variabile e tutti i blocchi e le copie dei blocchi dichiarate o creati all'interno scope 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). Più blocchi in un determinato ambito lessicale possono utilizzare simultaneamente una variabile condivisa.

Dalla documentazione circa __weak

__weak specifica un riferimento che non tenere in vita l'oggetto di riferimento. Un riferimento debole viene impostato su zero quando non vi sono riferimenti forti all'oggetto.

Quindi sono cose tecnicamente diverse. __block serve per impedire che la tua variabile venga copiata dall'ambito esterno nell'ambito del blocco. __weak è un puntatore debole auto-limitante.

Nota Ho detto tecnicamente, perché per il tuo caso faranno (quasi) la stessa cosa. L'unica differenza è se stai usando ARC o no. Se il progetto utilizza ARC ed è solo per iOS4.3 e versioni successive, utilizzare __weak.Assicura che il riferimento sia impostato su zero se il riferimento globale dello scope è rilasciato in qualche modo. Se il tuo progetto non usa ARC o è per versioni precedenti del sistema operativo, usa __block.

C'è una sottile differenza qui, assicurati di averlo capito.

EDIT: Un altro pezzo del puzzle è __unsafe_unretained. Questo modificatore è quasi lo stesso di __weak ma per gli ambienti di runtime precedenti alla 4.3. TUTTAVIA, non è impostato su zero e può lasciarti con puntatori sospesi.

+0

Abbastanza chiaro, grazie. – HanXu

+1

È ancora applicabile a iOS7 usando ARC? Ho eseguito un profiler e vedo che i miei controller vengono rilasciati anche se non utilizzo __block o __weak e riferimento self in un blocco. –

+0

Per chi desidera vedere il documento: https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html, https://developer.apple.com/library/ios /documentation/Cocoa/Conceptual/Blocks/Articles/bxVariables.html –

5

Nella modalità di conteggio dei riferimenti manuale, __block id x; ha l'effetto di non mantenere x. In modalità ARC, __block id x; il valore predefinito è mantenere x (proprio come tutti gli altri valori). Per ottenere il comportamento della modalità di conteggio del riferimento manuale in ARC, è possibile utilizzare __unsafe_unretained __block id x ;. Come il nome __unsafe_unretained implica, tuttavia, avere una variabile non mantenuta è pericolosa (perché può penzolare) ed è quindi scoraggiata. Due opzioni migliori sono utilizzare __weak (se non è necessario supportare iOS 4 o OS X v10.6) o impostare il valore __block su nil per interrompere il ciclo di conservazione.

apple docs

0

Accanto risposte su __block vs __weak, c'è un altro modo per evitare di mantenere il ciclo nel vostro scenario.

@weakify(self); 
[self methodThatTakesABlock:^ { 
    @strongify(self); 
    [self doSomething]; 
}]; 

More Info about @Weakify @Strongify Marco