it-swarm.com.ru

В чем разница между ссылками __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;

точно так же здесь here

Я нашел другую часть в документе:

Примечание. В среде со сборщиком мусора, если вы примените оба модификатора __weak и __block к переменной, тогда блок не будет гарантировать, что она будет сохранена.

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

76
HanXu

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

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

Из документов о __слабом

__weak указывает ссылку, которая не поддерживает ссылочный объект живым. Слабая ссылка устанавливается равной нулю, когда нет сильных ссылок на объект.

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

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

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

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

105
Paul de Lange

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

Apple Docs

5
Andrei Shender

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

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

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

0
Jun Jie Gan

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

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

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