Сообщение об объекте __weak?
Что произойдет, если я отправлю сообщение на слабый объект? Передаёт ли сообщение сообщение объекту и удерживает его в памяти до возврата?
Я думаю об этом шаблоне:
__weak MyObject *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf doSomeAction];
});
Предполагая, что weakSelf
не равно нулю, когда сообщение отправлено, может ли оно быть отменено, пока работает doSomeAction
или он будет оставаться действительным до тех пор, пока doSomeAction
не вернется?
Ответы
Ответ 1
Из Документация Clang ARC:
Чтение происходит при выполнении преобразования lvalue-to-rval на объекте lvalue.
- Для объектов
__weak
текущий указатель сохраняется и затем отпускается в конце текущего полного выражения. Это должно выполняться атомарно в отношении присвоений и окончательной версии пункта.
Сообщения слабой ссылки выполняют преобразование lvalue-to-rval в переменной, что означает, что значение слабой ссылки будет сохранено, а затем выпущено в конце текущего полного выражения (в основном, в заявлении). Это в основном эквивалентно назначению сильной переменной, объем которой длится только для текущего оператора, а затем передает эту сильную переменную.
Вывоз здесь - это если вы хотите сообщить слабую переменную один раз и никогда не касаться ее снова, и вам не нужны побочные эффекты оценки аргументов метода в случае, когда заканчивается слабая ссылка nil
, затем перейдите и сообщите о слабой ссылке напрямую. Но если вам нужно дважды ссылаться на слабую ссылку (в отдельных операторах) или побочные эффекты оценки аргументов, то перед продолжением следует назначить сильную переменную и проверить не-t21.
Ответ 2
Вы спросили:
Предполагая, что weakSelf
является не nil
при отправке сообщения, может ли он быть освобожден, если работает doSomeAction
, или он будет оставаться действительным до тех пор, пока doSomeAction
не вернется?
Да, он остается недействительным до тех пор, пока doSomeAction
не вернется, он сохраняется и для остальной части блока. Рассмотрим следующее:
- (void)dealloc
{
NSLog(@"%s", __FUNCTION__);
}
- (void)startBackgroundOperation
{
__weak MyObject * weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[weakSelf doSomeAction];
sleep(5);
[weakSelf doSomeAction2];
});
sleep(1);
}
- (void)doSomeAction
{
NSLog(@"%s", __FUNCTION__);
}
- (void)doSomeAction2
{
NSLog(@"%s", __FUNCTION__);
}
В этом примере я удостоверяюсь, что объект находился в области действия при запуске блока, но пусть он выпадает из области видимости между doSomeAction
и doSomeAction2
, но блок, похоже, сохраняет его для завершения блока, Но если я прокомментирую вызов doSomeAction
, ссылка weak
будет nil
к тому времени, когда она дойдет до doSomeAction2
, как и ожидалось.
Как в стороне, в WWDC 2011 - # 322 - Objective-C Продвижение в глубину, они указывают (около 27:00 мин. в видео), они отмечают, что если вы разыгрываете weakSelf
, у вас должна быть локальная сильная ссылка внутри блока отправки, чтобы защитить себя в состоянии гонки, таким образом:
__weak MyClass *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
MyClass *strongSelf = weakSelf;
if (strongSelf)
[strongSelf->myView doSomeViewAction];
});
Это сохранит его на протяжении всего блока (если он не был освобожден к тому времени, когда был выполнен блок).