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

¿Cómo puedo evitar esta advertencia en xcode? Aquí está el fragmento de código:

[player(AVPlayer object) addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100) queue:nil usingBlock:^(CMTime time) { current+=1; if(current==60) { min+=(current/60); current = 0; } [timerDisp(UILabel) setText:[NSString stringWithFormat:@"%02d:%02d",min,current]];///warning occurs in this line }]; 

Aquí, la captura de self entra con el acceso de propiedad implícito de self.timerDisp : no puede referirse a self o a las propiedades de self desde dentro de un bloque que será retenido por self .

Puede evitar esto creando una referencia débil a self antes de acceder a timerDisp dentro de su bloque:

 __weak typeof(self) weakSelf = self; [player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100) queue:nil usingBlock:^(CMTime time) { current+=1; if(current==60) { min+=(current/60); current = 0; } [weakSelf.timerDisp setText:[NSString stringWithFormat:@"%02d:%02d",min,current]]; }]; 
 __weak MyClass *self_ = self; // that's enough self.loadingDidFinishHandler = ^(NSArray *receivedItems, NSError *error){ if (!error) { [self_ showAlertWithError:error]; } else { self_.items = [NSArray arrayWithArray:receivedItems]; [self_.tableView reloadData]; } }; 

Y una cosa muy importante para recordar: no use variables de instancia directamente en el bloque, utilícelas como propiedades del objeto débil, muestra:

 self.loadingDidFinishHandler = ^(NSArray *receivedItems, NSError *error){ if (!error) { [self_ showAlertWithError:error]; } else { self_.items = [NSArray arrayWithArray:receivedItems]; [_tableView reloadData]; // BAD! IT ALSO WILL BRING YOU TO RETAIN LOOP } }; 

y no olvides hacer:

 - (void)dealloc { self.loadingCompletionHandler = NULL; } 

Puede aparecer otro problema si va a pasar una copia débil no retenida por cualquier objeto:

 MyViewController *vcToGo = [[MyViewCOntroller alloc] init]; __weak MyViewController *vcToGo_ = vcToGo; self.loadingCompletion = ^{ [vcToGo_ doSomePrecessing]; }; 

si vcToGo será desasignado y luego se dispara este bloque, creo que se bloqueará con un selector no reconocido en una papelera que ahora contiene la variable vcToGo_ . Intenta controlarlo

Mejor versión

 __strong typeof(self) strongSelf = weakSelf; 

Crea una referencia fuerte a esa versión débil como la primera línea en tu bloque. Si aún existe uno cuando el bloque comienza a ejecutarse y no ha vuelto a cero, esta línea asegura que persista a lo largo de la vida útil de ejecución del bloque.

Entonces todo sería así:

 // Establish the weak self reference __weak typeof(self) weakSelf = self; [player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100) queue:nil usingBlock:^(CMTime time) { // Establish the strong self reference __strong typeof(self) strongSelf = weakSelf; if (strongSelf) { [strongSelf.timerDisp setText:[NSString stringWithFormat:@"%02d:%02d",min,current]]; } else { // self doesn't exist } }]; 

He leído este artículo muchas veces. Este es un excelente artículo de Erica Sadun sobre cómo evitar problemas al usar bloques y NSNotificationCenter


Swift actualización:

Por ejemplo, en forma rápida un método simple con bloque de éxito sería:

 func doSomeThingWithSuccessBlock(success: () -> ()) { success() } 

Cuando llamamos a este método y necesitamos usar self en el bloque de éxito. Utilizaremos el [weak self] y las funciones de guard let .

  doSomeThingWithSuccessBlock { [weak self] () -> () in guard let strongSelf = self else { return } strongSelf.gridCollectionView.reloadData() } 

Este llamado baile fuerte-débil es utilizado por el popular proyecto de código abierto Alamofire .

Para más información echa un vistazo a swift-style-guide

En otra respuesta, Tim dijo:

no puede referirse a uno mismo o a las propiedades de uno mismo desde dentro de un bloque que será fuertemente retenido por uno mismo.

Esto no es del todo cierto. Está bien que hagas esto siempre que rompas el ciclo en algún momento. Por ejemplo, supongamos que tienes un temporizador que dispara que tiene un bloque que se conserva y también guardas una fuerte referencia al temporizador en sí mismo. Esto está perfectamente bien si siempre sabes que destruirás el temporizador en algún momento y romperás el ciclo.

En mi caso justo ahora, tuve esta advertencia para el código que hizo:

 [x setY:^{ [x doSomething]; }]; 

Ahora sé que el clang solo producirá esta advertencia si detecta que el método comienza con “set” (y otro caso especial que no mencionaré aquí). Para mí, sé que no hay peligro de que haya un bucle de retención, así que cambié el nombre del método a “useY:” Por supuesto, eso podría no ser apropiado en todos los casos y generalmente querrás usar una referencia débil, pero Pensé que valía la pena señalar mi solución en caso de que ayudara a otros.

Agregar dos centavos para mejorar la precisión y el estilo. En la mayoría de los casos, solo utilizará uno o dos miembros de self en este bloque, lo más probable es que simplemente actualice un control deslizante. Casting self es excesivo. En cambio, es mejor ser explícito y lanzar solo los objetos que realmente necesita dentro del bloque. Por ejemplo, si se trata de una instancia de UISlider* , por ejemplo, _timeSlider , haga lo siguiente antes de la statement de bloque:

 UISlider* __weak slider = _timeSlider; 

Entonces solo usa el slider dentro del bloque. Técnicamente, esto es más preciso ya que reduce el ciclo de retención de potencial a solo el objeto que necesita, no todos los objetos dentro de self .

Ejemplo completo:

 UISlider* __weak slider = _timeSlider; [_embeddedPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:nil usingBlock:^(CMTime time){ slider.value = time.value/time.timescale; } ]; 

Además, lo más probable es que el objeto que se está convirtiendo en un puntero débil ya sea un puntero débil dentro de self mismo y minimice o elimine por completo la probabilidad de un ciclo de retención. En el ejemplo anterior, _timeSlider es en realidad una propiedad almacenada como una referencia débil, por ejemplo:

 @property (nonatomic, weak) IBOutlet UISlider* timeSlider; 

En términos de estilo de encoding, como en C y C ++, las declaraciones de variables se leen mejor de derecha a izquierda. Declarar SomeType* __weak variable en este orden se lee de forma más natural de derecha a izquierda como: variable is a weak pointer to SomeType .