2012-01-10 13 views
5

Mike Ash has written this introduction to ARC gdzie wprowadza coś takiego:Kiedy i dlaczego chcę zadeklarować zmienną lokalną jako __weak przy użyciu ARC?

__weak Foo *_weakFoo = [object foo]; 

Dlaczego miałbym to zrobić, dla zmiennej czasowej lokalnym? __weak to odwołanie do zerowania, które automatycznie ustawia wskaźnik _weakFoo na zero, gdy tylko obiekt referencyjny zostanie zwolniony. Również __weak jest dostępna tylko w iOS> = 5.

Kiedy chciałbym popaść w kłopoty, kiedy po prostu to zrobić ?:

Foo *_weakFoo = [object foo]; 

To jest zawsze oczekuje się zwrócić obiekt lub zerowa. Moje przypuszczenie jest takie:

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

Jedną rzeczą, która nadal robaki mnie z łuku jest: Kiedy to wiem, że nie muszę już obiekt? Twierdzę, że kiedy ustawiam wskaźnik na zero lub coś innego, to odkryje on, że obiekt, do którego wcześniej się odwołał, nie jest już potrzebny temu właścicielowi i dlatego może odejść. Ale chodzi o to, że ustawiłem go na zero. Więc i tak jest zero!

Więc kiedy zmienilibyśmy lokalną zmienną __, co za szalona rzecz, muszę zrobić gdzie indziej, że naprawdę tego potrzebuję?

Odpowiedz

9

Używam zmiennych lokalnych __weak, jeśli muszę manipulować self wewnątrz bloku, aby uniknąć cyklu zatrzymania. Rozważmy ten przykład, w którym używam GCD i bloków, aby wykonać żądanie sieciowe dla łańcucha, a następnie ustawiając go na etykiecie zadeklarowanej przez klasę, w tym przypadku, 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

Co jednak może być cykl zatrzymania? – openfrog

+1

@openfrog - Ten konkretny blok może nie być narażony na największe ryzyko bycia cyklem zatrzymania, ale taki, na którym natrafiłem, byłby blokowym obserwatorem dla powiadomień (za pomocą '-addObserverForName NSNotificationCenter: object: queue: usingBlock:'). Jeśli ustawisz takiego obserwatora w obiekcie i odniesiesz się do czegoś na "ja", ustawisz cykl, gdy obiekt będzie trzymał się bloku, a blok będzie trzymał się tego obiektu. –

+2

Po napisaniu tego zdałem sobie sprawę, że nie jest to najlepszy przykład, ponieważ dispatch_async() kopiuje blok, ale tylko do końca metody. Lepszym przykładem byłoby użycie NSBlockOperation, ponieważ instancja takiego obiektu przechodzi przez blok życia przez cały okres istnienia obiektu, co sprawia, że ​​cykle zatrzymania są bardziej prawdopodobne. –

Powiązane problemy