Capturar 'uno mismo' con fuerza en este bloque es probable que conduzca a un ciclo de retención

Necesito bloque. Pero el comstackdor emite una advertencia

"Captar 'uno mismo' con fuerza en este bloque es probable que conduzca a un ciclo de retención"

__weak typeof(self) weakSelf = self; [generalInstaImage setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:data[@"images"][@"low_resolution"][@"url"]]] placeholderImage:[UIImage imageNamed:@"Default"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { NSLog(@"success"); [generalInstaImage setImage: image]; [weakSelf saveImage:generalInstaImage.image withName:data[@"id"]]; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { NSLog(@"fail"); }]; 

Intento escribir el ejemplo como weakSelf.generalInstaImage , pero luego el comstackdor genera un error y no comstack.

Cuando reciba esta advertencia:

Capturarse fuertemente en este bloque es probable que conduzca a un ciclo de retención

Debe revisar su bloque para:
(a) cualquier reference explícita a self
(b) cualquier reference implícita a self causada al hacer reference a cualquier variable de instancia.

Imaginemos que tenemos una propiedad de class simple que era un bloque (esto experimentará las mismas advertencias de "ciclo de retención" que su pregunta, pero mantendrá mis ejemplos un poco más simples):

 @property (nonatomic, copy) void (^block)(void); 

Y supongamos que teníamos alguna otra propiedad de class que queríamos usar dentro de nuestro bloque:

 @property (nonatomic, strong) NSString *someString; 

Si hace reference a self dentro del bloque (en mi ejemplo a continuación, en el process de acceder a esta propiedad), obviamente recibirá esa advertencia sobre el riesgo del ciclo de retención:

 self.block = ^{ NSLog(@"%@", self.someString); }; 

Eso se soluciona a través del patrón que sugirió, a saber:

 __weak typeof(self) weakSelf = self; self.block = ^{ NSLog(@"%@", weakSelf.someString); }; 

Menos obvio, también recibirá la advertencia "retener ciclo" si hace reference a una variable de instancia de la class dentro del bloque, por ejemplo:

 self.block = ^{ NSLog(@"%@", _someString); }; 

Esto se debe a que la variable de instancia _someString lleva una reference implícita a self , y en realidad es equivalente a:

 self.block = ^{ NSLog(@"%@", self->_someString); }; 

Uno podría estar inclinado a usar weakSelf patrón weakSelf nuevamente, lo que resulta en la weakSelf->_someString , pero el comstackdor le advertirá sobre esto:

No se __weak reference de un puntero __weak debido a un posible valor nulo causado por la condición de carrera, asigne primero una variable strong

Por lo tanto, resuelve esto usando el patrón weakSelf , pero también crea una variable strong local dentro del bloque y usa eso para desreferencer la variable de instancia:

 __weak typeof(self) weakSelf = self; self.block = ^{ __strong typeof(self) strongSelf = weakSelf; if (strongSelf) { NSLog(@"%@", strongSelf->_someString); // or better, just use the property // // NSLog(@"%@", strongSelf.someString); } }; 

Como un aparte, esta creación de una strong reference local, strongSelf , dentro del bloque tiene otras ventajas también, es decir, que si el bloque de finalización se ejecuta de forma asíncrona en un hilo diferente, no tiene que preocuparse de que el self se desasigne mientras el El bloque se está ejecutando, lo que genera consecuencias no deseadas.

Este patrón weakSelf / strongSelf es muy útil cuando se trata de properties de bloque y desea evitar ciclos de retención (también conocidos ciclos de reference), pero al mismo time garantizar que ese self usuario no pueda desasignarse en el medio de la ejecución del bloque de finalización.

Para su información, Apple analiza este patrón en la discusión sobre "ciclos no triviales" más abajo en la sección Usar clasificadores de por vida para evitar ciclos de reference fuertes de la transición a las notas de la versión de ARC.


weakSelf.generalInstaImage que recibió un "error" cuando hizo reference a weakSelf.generalInstaImage en su ejemplo. Esta es la manera correcta de resolver esta advertencia de "ciclo de retención", por lo que si recibió alguna advertencia, debe compartirla con nosotros, así como mostrarnos cómo declaró la propiedad.

Use __unsafe_unretained typeof(self) weakSelf = self