В чем разница между ссылкой __weak и __block?

Я читаю документацию 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 для переменной, тогда блок не гарантирует, что он будет сохранен.

Итак, я полностью озадачен.

Ответ 1

Из документов о __block

__ Блочные переменные живут в хранилище, которые разделяются между лексической областью переменной и всеми блоками и блочными копиями, объявленными или созданными в пределах лексической области переменных. Таким образом, хранилище сохранится при уничтожении кадра стека, если любые копии блоков, объявленных в пределах кадра, выйдут за пределы кадра (например, путем размещения где-то для последующего выполнения). Несколько блоков в данной лексической области могут одновременно использовать общую переменную.

Из документов о __weak

__ weak указывает ссылку, которая не сохраняет объект ссылки. Слабая ссылка устанавливается равной нулю, когда нет сильных ссылок на объект.

Итак, это технически разные вещи. __block - остановить копирование переменной из вашей внешней области в область вашего блока. __weak - это самоограничивающий слабый указатель.

Примечание. Я сказал технически, потому что для вашего дела они будут делать (почти) то же самое. Разница только в том, что вы используете ARC или нет. Если ваш проект использует ARC и предназначен только для iOS4.3 и выше, используйте __weak. Это гарантирует, что ссылка будет установлена ​​на nil, если ссылка на глобальную область действия будет выпущена как-то. Если ваш проект не использует ARC или предназначен для более старых версий ОС, используйте __block.

Здесь есть тонкая разница, убедитесь, что вы это поняли.

EDIT: Еще одна часть головоломки - __unsafe_unretained. Этот модификатор почти такой же, как __weak, но для среды выполнения до 4.3. ОДНАКО, он не установлен в ноль и может оставить вас с подвесными указателями.

Ответ 2

В режиме ручной подсчета ссылок __block id x; имеет эффект не удерживания x. В режиме ARC __block id x; по умолчанию сохраняется x (как и все остальные значения). Чтобы получить поведение режима подсчета ручной ссылки в ARC, вы можете использовать __unsafe_unredtained __block id x;. Однако, поскольку имя __unsafe_unretained подразумевает, что наличие незадерживаемой переменной опасно (потому что оно может болтаться) и поэтому обескураживается. Два лучших варианта - либо использовать __weak (если вам не нужно поддерживать iOS 4 или OS X v10.6), либо установить значение __block в nil для прерывания цикла сохранения.

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

Ответ 3

Помимо других ответов на __block против __weak, есть еще один способ избежать сохранения цикла в вашем сценарии.

@weakify(self);
[self methodThatTakesABlock:^ {
    @strongify(self);
    [self doSomething];
}];

Подробнее о @Weakify @Strongify Macro

Ответ 4

При использовании self в блоке следует использовать __weak, а не __block, так как он может сохранить себя.

Если вам нужна сильная личность, то вы можете использовать так:

__weak MyClass *weakSelf = self;
[self methodThatTakesABlock:^{
    if (weakSelf) {
        __strong MyClass *strongSelf = weakSelf;
        [strongSelf doSomething];
    }
}];