Сообщение об объекте __weak? - программирование

Сообщение об объекте __weak?

Что произойдет, если я отправлю сообщение на слабый объект? Передаёт ли сообщение сообщение объекту и удерживает его в памяти до возврата?

Я думаю об этом шаблоне:

__weak MyObject *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    [weakSelf doSomeAction];
});

Предполагая, что weakSelf не равно нулю, когда сообщение отправлено, может ли оно быть отменено, пока работает doSomeAction или он будет оставаться действительным до тех пор, пока doSomeAction не вернется?

4b9b3361

Ответ 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];
});

Это сохранит его на протяжении всего блока (если он не был освобожден к тому времени, когда был выполнен блок).