visual pods for objective-c cocoa-touch automatic-ref-counting avplayer retain

objective c - pods - capturarse fuertemente en este bloque es probable que conduzca a un ciclo de retenciĆ³n



java project gitignore (5)

Mejor version

__strong typeof(self) strongSelf = weakSelf;

Cree una referencia fuerte a esa versión débil como la primera línea en su bloque. Si el self sigue existiendo cuando el bloque comienza a ejecutarse y no ha retrocedido a cero, esta línea garantiza que persista durante toda la vida útil de ejecución del bloque.

Así que 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

Actualización rápida:

Por ejemplo, en swift 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. Usaremos el [weak self] y las características de la función de guard let .

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

Esta llamada danza fuerte-débil es utilizada por el popular proyecto de código abierto Alamofire .

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

¿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 }];


Añadiendo dos centavos para mejorar la precisión y el estilo. En la mayoría de los casos, solo usarás uno o un par de miembros de self en este bloque, probablemente solo para actualizar un control deslizante. Casting self es una exageración. En su lugar, es mejor ser explícito y lanzar solo los objetos que realmente necesitas dentro del bloque. Por ejemplo, si es una instancia de UISlider* , digamos, _timeSlider , simplemente haga lo siguiente antes de la declaración de bloque:

UISlider* __weak slider = _timeSlider;

Luego solo usa el slider dentro del bloque. Técnicamente, esto es más preciso, ya que reduce el ciclo de retención potencial al objeto que necesita, no a 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, minimizando o eliminando completamente 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 codificación, al igual que con C y C ++, las declaraciones de variables se leen mejor de derecha a izquierda. La declaración de SomeType* __weak variable en este orden se lee de forma más natural de derecha a izquierda ya que: variable is a weak pointer to SomeType .


En otra respuesta, Tim dijo:

no puedes referirte a ti mismo o propiedades en ti mismo desde un bloque que será retenido fuertemente por ti 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 tiene un temporizador que se dispara y que tiene un bloque que se conserva a sí mismo y también mantiene una referencia fuerte 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 tenía:

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

Ahora sé que 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á usar una referencia débil, pero Pensé que valía la pena señalar mi solución en caso de que ayude a otros.


La captura del self aquí viene con su acceso implícito a la propiedad de self.timerDisp ; no puede referirse a self o propiedades en self desde un bloque que será retenido fuertemente por el self .

Puede timerDisp 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 las 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 te olvides de hacer

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

puede aparecer otro problema si pasa una copia débil de un objeto no retenido por nadie:

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

Si vcToGo se desasignará y luego se vcToGo este bloque, creo que se bloqueará con un selector no reconocido a una papelera que ahora contiene la variable vcToGo_ . Intenta controlarlo.