У чому різниця між __слабким та __блоковим посиланням?


80

Я читаю документацію Xcode, і ось щось мене бентежить:

__block typeof(self) tmpSelf = self;
[self methodThatTakesABlock:^ {
    [tmpSelf doSomething];
}];

З документації копіюється:

Блок формує сильне посилання на змінні, які він фіксує. Якщо ви використовуєте selfвсередині блоку, блок формує сильне посилання на self, тому, якщо воно selfтакож має сильне посилання на блок (що зазвичай робиться), результат сильного посилального циклу. Щоб уникнути циклу, вам потрібно створити слабке (або __block) посилання на себе поза блоком, як у прикладі вище.

Я не розумію, що означає "слабкий (або __block )"?

Є

__block typeof(self) tmpSelf = self;

і

__weak typeof(self) tmpSelf = self;

точно так само тут?

У документі я знайшов ще один фрагмент:

Примітка. Якщо в середовищі, яке збирається сміттям, якщо ви застосуєте до змінної обидва модифікатори __weakта __blockмодифікатори, то блок не забезпечить його збереження.

Отже, я абсолютно спантеличений.

Відповіді:


109

З документації про __block

__block змінні живуть у сховищі, яке розподіляється між лексичним обсягом змінної та всіма блоками та копіями блоків, оголошеними або створеними в межах лексичного обсягу змінної. Таким чином, сховище переживе знищення кадру стека, якщо будь-які копії блоків, оголошені всередині кадру, виживуть і після кінця кадру (наприклад, потрапляючи в чергу десь для подальшого виконання). Кілька блоків у даній лексичній області можуть одночасно використовувати спільну змінну.

З документів про __слабкий

__weak визначає посилання, яке не утримує об'єкт, на який посилається. Слабке посилання встановлюється як нуль, коли немає сильних посилань на об'єкт.

Отже, це технічно різні речі. __block - зупинити копіювання змінної із зовнішньої області в область блоку. __weak - це саморозмежувальний слабкий вказівник.

Зауважте, що я сказав технічно, тому що для вашого випадку вони будуть робити (майже) те саме. Різниця лише в тому, використовуєте ви ARC чи ні. Якщо ваш проект використовує ARC і призначений лише для iOS4.3 і новіших версій, використовуйте __weak. Це гарантує, що посилання встановлено на нуль, якщо посилання на глобальну область якось випущено. Якщо ваш проект не використовує ARC або призначений для старих версій ОС, використовуйте __block.

Тут є тонка різниця, переконайтесь, що ви це розумієте.

EDIT: Ще одна частина головоломки __unsafe_unretention. Цей модифікатор майже такий же, як __weak, але для середовищ виконання до 4.3. Однак, він не встановлений на нуль і може залишити вас підвісними вказівниками.


1
Чи все ще це застосовно до iOS7, що використовує ARC? Я запустив профайлер і бачу, що мої контролери звільняються, навіть якщо я не використовую __block або __weak і посилання на себе в блоці.
Jay Q.


1
Як щодо їх спільного використання? __block _weak NSString *strEg;?
CyberMew

5

У ручному режимі підрахунку посилань __block id x; має наслідком не утримувати x. У режимі ARC __block id x; за замовчуванням зберігає x (як і всі інші значення). Щоб отримати поведінку режиму підрахунку посилань вручну за ARC, ви можете використовувати __unsafe_unretain __block id x ;. Однак, як випливає з назви __unsafe_unretain, наявність незатриманої змінної є небезпечним (оскільки вона може бовтатися) і тому не рекомендується. Два кращі варіанти - або використовувати __weak (якщо вам не потрібно підтримувати iOS 4 або OS X v10.6), або встановити значення __block на нуль, щоб порушити цикл збереження.

яблучні документи



0

Використовуючи self в блоці, слід використовувати __weak , а не __block оскільки він може зберегти self.

Якщо вам потрібне сильне самоврядування, ви можете скористатися таким чином:

__weak typeof(self) *weakSelf = self;
[self methodThatTakesABlock:^{
    if (weakSelf) {
        __strong typeof(self) *strongSelf = weakSelf;
        [strongSelf doSomething];
    }
}];
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.