2012-01-10 11 views
5

Mike Ash has written this introduction to ARC dove introduce qualcosa di simile:Quando e perché dovrei dichiarare una variabile locale come __weak usando ARC?

__weak Foo *_weakFoo = [object foo]; 

perché dovrei farlo per una variabile locale, temporanea? __weak è un riferimento di azzeramento che imposterà automaticamente il puntatore _weakFoo su zero non appena l'oggetto referenziato viene deallocato. Inoltre, __weak è disponibile solo in iOS> = 5.

Quando avrei incontrato difficoltà quando ho semplicemente faccio ?:

Foo *_weakFoo = [object foo]; 

Questo è sempre tenuto a restituire un oggetto o nullo. La mia ipotesi è questa:

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

Una cosa che ancora mi bug con arco è: quando si fa a sapere che non ho più bisogno di un oggetto? Direi che quando imposto un puntatore su nil o su qualcos'altro, si scopre che l'oggetto precedentemente referenziato non è più necessario da questo proprietario e quindi forse può andare via. Ma il punto è: l'ho impostato su zero. Quindi è comunque zero!

Quindi, quando è necessario un errore per una variabile locale, e quale tipo di cosa pazza devo fare da qualche altra parte in modo che ne abbia davvero bisogno?

risposta

9

Io uso le variabili locali __weak se devo manipolare self all'interno di un blocco per evitare un ciclo di conservazione. Considera questo esempio in cui sto utilizzando GCD e blocchi per eseguire una richiesta di rete per una stringa e quindi impostarla su un'etichetta dichiarata dalla classe, in questo 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

Come potrebbe esserci un ciclo di conservazione? – openfrog

+1

@openfrog - Questo particolare blocco potrebbe non essere a rischio maggiore di essere un ciclo di conservazione, ma quello che ho incontrato sarebbe osservatori basati su blocchi per le notifiche (usando NSNotificationCenter's -addObserverForName: object: queue: usingBlock: '). Se si imposta un tale osservatore in un oggetto e si fa riferimento a qualcosa su 'self', si imposta un ciclo mentre l'oggetto rimane sul blocco e il blocco rimane sull'oggetto. –

+2

Dopo aver scritto ciò, mi sono reso conto che questo non è il miglior esempio perché dispatch_async() copia il blocco, ma solo fino alla fine del metodo. Un esempio migliore sarebbe stato l'utilizzo di NSBlockOperation poiché un'istanza di tale proprietà possiede il blocco passato per la durata dell'oggetto, rendendo più probabili i cicli di conservazione. –

Problemi correlati