2012-01-10 1 views
5

Mike Ash has written this introduction to ARC где он вводит что-то вроде:Когда и почему я хочу объявить локальную переменную как __weak с помощью ARC?

__weak Foo *_weakFoo = [object foo]; 

Почему я хотел бы сделать это для локальной, временной переменной? __weak - это ссылка на обнуление, которая автоматически установит указатель _weakFoo на нуль, как только ссылочный объект будет освобожден. Кроме того, __weak доступна только в прошивкой> = 5.

Когда я запускаю в беду, когда я просто это сделать ?:

Foo *_weakFoo = [object foo]; 

Он всегда должен возвращать объект или ноль. Я думаю, это:

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

Одна вещь, которая до сих пор ошибки меня с ARC: Когда он знает, что я не нужен объект больше? Я утверждаю, что когда я устанавливаю указатель на нуль или что-то еще, он выясняет, что ранее упомянутый объект больше не нужен этому владельцу и, следовательно, может уйти. Но дело в том, что я установил его на ноль. Так что все равно!

Итак, когда будет __weak для локальной переменной иметь смысл, и о какой сумасшедшей вещи я должен делать где-то в другом месте, чтобы мне это действительно нужно?

ответ

9

Я использую локальные переменные __weak, если мне нужно манипулировать self внутри блока, чтобы избежать цикла сохранения. Рассмотрим этот пример, когда я использую GCD и блоки для выполнения сетевого запроса для строки, а затем устанавливаю его на этикетке, объявленной классом, в этом случае 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

Каким может быть цикл удержания? – openfrog

+1

@openfrog - Этот конкретный блок может не подвергаться наибольшему риску быть циклом сохранения, но тот, с которым я столкнулся, будет блочным наблюдателем для уведомлений (используя NSNotificationCenter's -addObserverForName: object: queue: usingBlock: '). Если вы настроили такого наблюдателя в объекте и ссылаетесь на что-то на 'self', вы настроите цикл, когда объект держится на блоке, и блок удерживает объект. –

+2

После написания этого я понял, что это не лучший пример, потому что dispatch_async() копирует блок, но только до конца метода. Лучшим примером могло бы быть использование NSBlockOperation, поскольку экземпляр такого объекта принадлежит переданному в блоке времени жизни объекта, что делает циклы сохранения более вероятными. –