capturar uno mismo fuertemente 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
}];
Author: devios1, 2013-01-28

5 answers

La captura de self aquí viene con su acceso implícito a la propiedad de self.timerDisp - no puede hacer referencia a self o propiedades en self desde dentro de un bloque que será fuertemente retenido por self.

Puedes evitar esto creando una referencia débil a self antes de acceder a timerDisp dentro de tu 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]];
                                            }];
 493
Author: Tim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-28 06:39:16
__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 a recordar: no utilice variables de instancia directamente en el bloque, úselo como propiedades de un objeto débil, ejemplo:

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 disparará este bloque, creo que se bloqueará con el selector no reconocido a una papelera que ahora contiene la variable vcToGo_. Tratar de controlar se.

 51
Author: iiFreeman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-18 16:51:40

Mejor versión

__strong typeof(self) strongSelf = weakSelf;

Crea una referencia fuerte a esa versión débil como la primera línea de tu bloque. Si self todavía existe cuando el bloque comienza a ejecutarse y no ha caído de nuevo a nil, esta línea asegura que persiste durante toda la vida de ejecución del bloque.

Así que todo sería así: {[12]]}

// 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 en Cómo Evitar Problemas Cuando Usando 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. Vamos a utilizar el [weak self] y guard let características.

    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 abiertoAlamofire.

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

 37
Author: Warif Akhand Rishi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-04 11:23:04

En otra respuesta, Tim dijo:

No se puede hacer referencia a uno mismo o 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 y cuando rompas el ciclo en algún momento. Por ejemplo, digamos que tienes un temporizador que dispara que tiene un bloque que retiene a sí mismo y también mantiene una fuerte referencia al temporizador en sí mismo. Esto está perfectamente bien si siempre sabes que destruirás el temporizador en algunos apuntan y rompen el ciclo.

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

[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 vale la pena señalar mi solución en caso de que ayude a otros.

 14
Author: Chris Suter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-25 00:51:23

Añadiendo dos centavos para mejorar la precisión y el estilo. En la mayoría de los casos, solo utilizará uno o un par de miembros de self en este bloque, lo más probable es que solo actualice un control deslizante. Casting self es exagerado. En su lugar, es mejor ser explícito y lanzar solo los objetos que realmente necesita 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 simplemente use slider dentro del bloque. Técnicamente esto es más preciso, ya que reduce el ciclo de retención potencial a solo el 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 lanza a un puntero débil ya sea un puntero débil dentro de self, así como minimizar o eliminar 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 codificación, como con C y C++, las declaraciones de variables se leen mejor de derecha a izquierda. Declarar SomeType* __weak variable en este orden se lee más naturalmente de derecha a izquierda como: variable is a weak pointer to SomeType.

 1
Author: Luis Artola,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-22 18:54:04