2012-01-10 16 views
5

Mike Ash has written this introduction to ARC donde introduce algo como:¿Cuándo y por qué querría declarar una variable local como __weak usando ARC?

__weak Foo *_weakFoo = [object foo]; 

¿Por qué querría hacer eso por una variable local, temporal? __weak es una referencia de puesta a cero que establecerá el puntero _weakFoo automáticamente en cero tan pronto como el objeto al que se hace referencia se desasigna. Además, __weak sólo está disponible en iOS> = 5.

Cuando iba a tener problemas cuando hago simplemente esto ?:

Foo *_weakFoo = [object foo]; 

Esto siempre se espera que regrese un objeto o nula. Mi opinión es la siguiente:

Foo *_weakFoo = [object foo]; 
[self doSomethingStupid]; // does something bad so foo gets deallocated 
[_weakFoo doIt]; // CRASH! msg sent to deallocated instance 0x123456 

Una cosa que todavía me molesta con arco es: ¿Cuándo se sabe que no necesito un objeto más? Argumentaría que cuando establezco un puntero a cero o a otra cosa, se da cuenta de que el objeto al que se hace referencia anteriormente ya no es necesario para este propietario y, por lo tanto, puede desaparecer. Pero el punto es: lo configuré en cero. ¡Así que es nada!

Entonces, cuándo tendría sentido buscar una variable local, y qué tipo de locura debo hacer en otro lugar para que realmente lo necesite?

Respuesta

9

Yo uso __weak variables locales si tengo que manipular self dentro de un bloque para evitar un ciclo de retención. Considere este ejemplo en el que estoy usando GCD y bloques para realizar una solicitud de red para una cadena, y luego configurarla en una etiqueta declarada por la clase, en este caso, TurtlesViewController.

__weak TurtlesViewController *weakSelf = self; 
dispatch_queue_t networkQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 

dispatch_async(networkQueue, ^{ 

    // Kick off a network task for some data that is going to populate a label declared on our class 
    NSString *returnString = [networkDataSource retrieveTurtleTime]; 

    // Dispatch back to the main thread to populate the UILabel 
    dispatch_async(dispatch_get_main_queue(), ^{ 

     // Using self.label here creates a retain cycle. Self owns the block and the block has captured self 
     self.label.text = returnString; 

     // Instead, we use weakSelf for our reference to the label as it will be torn down by ARC at the end of the loop. 
     weakSelf.label.text = returnString; 
    }); 
}); 
+1

¿Cómo podría haber un ciclo de retención? – openfrog

+1

@openfrog - Este bloque en particular podría no tener el mayor riesgo de ser un ciclo de retención, pero uno con el que me he encontrado sería un observador basado en bloques para notificaciones (usando NSNotificationCenter '-addObserverForName: object: queue: usingBlock:') Si configura tal observador en un objeto, y se refiere a algo en 'self', configurará un ciclo cuando el objeto se aferra al bloque y el bloque se aferra al objeto. –

+2

Después de escribir esto, me di cuenta de que este no es el mejor ejemplo porque dispatch_async() copia el bloque, pero solo hasta el final del método. Un mejor ejemplo habría sido el uso de NSBlockOperation ya que una instancia de este posee el bloque pasado en la vida del objeto, haciendo que los ciclos de retención sean más probables. –

Cuestiones relacionadas