68

estoy leyendo la documentación de Xcode, y aquí es algo que me intriga:¿Cuál es la diferencia entre una referencia __weak y __block?

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

El siguiente es copiado de la documentación:

Se forma un bloque de una fuerte referencia a las variables que captura. Si utiliza self dentro de un bloque, el bloque constituye una referencia fuerte al self, por lo que si self también hace una referencia fuerte al bloque (que típicamente es ), se obtiene un fuerte ciclo de referencia. Para evitar el ciclo, necesita para crear una referencia débil (o __block) a sí mismo fuera del bloque, como en el ejemplo anterior.

No entiendo qué significa 'a weak (or __block)'?

Es

__block typeof(self) tmpSelf = self; 

y

__weak typeof(self) tmpSelf = self; 

exactamente lo mismo aquí

me encontré con otra pieza en el documento:?

Nota: En una recogida de basura entorno, si aplica ambosModificadores dey __block a una variable, entonces el bloque no asegurará que se mantenga activo.

Por lo tanto, estoy totalmente perplejo.

Respuesta

99

A partir de los documentos sobre __block

las variables __block viven en el almacenamiento que se comparte entre el ámbito léxico de la variable y todos los bloques y las copias de bloques declarados o creados dentro de ámbito léxico de la variable. Por lo tanto, el almacenamiento sobrevivirá a la destrucción del marco de pila si cualquier copia de los bloques declarados dentro del marco sobrevive más allá del final del marco (por ejemplo, al ser enrutado en algún lugar para su posterior ejecución). Múltiples bloques en un alcance léxico dado pueden usar simultáneamente una variable compartida.

A partir de los documentos sobre __weak

__weak especifica una referencia que no guarda el objeto referenciado con vida. Una referencia débil se establece en cero cuando no hay referencias fuertes al objeto.

Por lo tanto, son cosas técnicamente diferentes. __block es para detener la copia de su variable desde su alcance externo en su alcance de bloque. __weak es un puntero débil auto delimitador.

Nota que dije técnicamente, porque para su caso harán (casi) lo mismo. La única diferencia es si está usando ARC o no. Si su proyecto usa ARC y es solo para iOS4.3 y superior, use __weak.Asegura que la referencia se establece en nil si la referencia de alcance global se libera de alguna manera. Si su proyecto no usa ARC o es para versiones anteriores del sistema operativo, use __block.

Aquí hay una sutil diferencia, asegúrese de entenderlo.

EDITAR: Otra pieza del rompecabezas es __unsafe_unretained. Este modificador es casi el mismo que __weak pero para entornos de tiempo de ejecución pre 4.3. SIN EMBARGO, no está configurado en cero y puede dejarlo con punteros colgantes.

+0

Muy claro, gracias. – HanXu

+1

¿Sigue siendo aplicable a iOS7 con ARC? Ejecuté un generador de perfiles y veo que mis controladores están siendo liberados incluso si no uso __block o __weak y me refiero a uno mismo en un bloque. –

+0

Para alguien que quiera ver el 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

En el modo de conteo de referencia manual, __block id x; tiene el efecto de no retener x. En el modo ARC, __block id x; se predetermina a retener x (al igual que todos los demás valores). Para obtener el comportamiento del modo de conteo manual de referencia bajo ARC, puede usar __unsafe_unretained __block id x ;. Como el nombre __unsafe_unretained implica, sin embargo, tener una variable no retenida es peligroso (porque puede colgar) y, por lo tanto, se desalienta. Dos mejores opciones son usar __weak (si no necesita soportar iOS 4 u OS X v10.6), o establecer el valor de __block en nil para romper el ciclo de retención.

apple docs

0

Al lado de otras respuestas en __block vs __weak, hay otra forma de evitar el ciclo de retener en su escenario.

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

More Info about @Weakify @Strongify Marco

Cuestiones relacionadas