Я читаю документацию 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];
}
}];