De los Transitioning to ARC Release Notes¿Por qué tenemos que establecer __block variable en nil?
Calificadores uso en la vida para evitar los ciclos de referencia fuertes
Puede utilizar calificadores de por vida para evitar ciclos de referencia fuertes. Para el ejemplo , normalmente si tiene un gráfico de objetos organizados en una jerarquía de elementos primarios y secundarios y los padres necesitan referirse a sus hijos y viceversa, entonces la relación padre-hijo es fuerte y hijo-a -relacion parental débil Otras situaciones pueden ser más sutiles, particularmente cuando involucran objetos de bloque.
En el modo de recuento de referencia manual,
__block id x;
tiene el efecto de no que retienex
. En el modo ARC,__block id x;
se predetermina a retenerx
(solo como todos los demás valores). Para obtener el comportamiento del modo de recuento de referencia manual 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 es por lo tanto desaconsejado. Dos mejores opciones son usar__weak
(si es no necesita admitir iOS 4 u OS X v10.6), o establecer el valor__block
ennil
para interrumpir el ciclo de retención.
Bien, entonces ¿qué hay de diferente en __block
variable?
¿Por qué configurar nil
aquí? ¿La variable __block
se retiene dos veces? ¿Quién tiene toda la referencia? ¿El bloque? El montón? ¿La pila? ¿La amenaza? ¿El qué?
El siguiente fragmento de código ilustra este problema utilizando un patrón que a veces se utiliza en el recuento manual de referencias.
MyViewController *myController = [[MyViewController alloc] init…];
// ...
myController.completionHandler = ^(NSInteger result) {
[myController dismissViewControllerAnimated:YES completion:nil];
};
[self presentViewController:myController animated:YES completion:^{
[myController release];
}];
Como se ha descrito, en cambio, se puede utilizar un calificador __block
y establecer la variable myController a nil
en el controlador de ejecución:
MyViewController * __block myController = [[MyViewController alloc] init…]; //Why use __block. my controller is not changed at all
// ...
myController.completionHandler = ^(NSInteger result) {
[myController dismissViewControllerAnimated:YES completion:nil];
myController = nil; //Why set to nil here? Is __block variable retained twice? Who hold all the reference? The block? The heap? The stack? The thread? The what?
};
También por qué myController
no se ajusta a nil
por el compilador. ¿Por qué tenemos que hacer eso? Parece que el compilador sabe cuándo myController ya no se volverá a utilizar, es decir, cuando caduque el bloque.
"Pero el bloque en sí también retendrá el objeto porque está fuertemente referenciado dentro del bloque". ¿Por qué? Cierre. –
¿De qué manera la adición de __block hace alguna diferencia de todos modos? –
Cuando un bloque captura un puntero a un objeto objetivo-c, ese objeto se mantendrá a menos que use '__weak' o' __unsafe_unretained' (o '__block' en código que no sea ARC). –