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.