Ответ 1
__block
- это определитель хранилища. Он указывает, что переменная должна быть непосредственно захвачена блоком, а не копированием. Это полезно, если вам нужно изменить исходную переменную, как в следующем примере
__block NSString *aString = @"Hey!";
void(^aBlock)() = ^{ aString = @"Hello!" }; // without __block you couldn't modify aString
NSLog(@"%@", aString); // Hey!
aBlock();
NSLog(@"%@", aString); // Hello!
В ARC это приводит к тому, что переменная автоматически сохраняется, поэтому ее можно безопасно ссылаться в рамках реализации блока. В предыдущем примере затем aString
отправляется сообщение retain
при захвате в контексте блока.
Не то, чтобы это не подтвердилось в MRC (Manual Reference Counting), где эта переменная указана без сохранения.
Отмечая его как __weak
, эта переменная не сохраняется, поэтому блок непосредственно ссылается на нее, но не сохраняет ее. Это потенциально опасно, поскольку в случае, если блок живет дольше, чем переменная, поскольку он будет ссылаться на память мусора (и может произойти сбой).
Здесь соответствующий абзац из clang doc:
В языках Objective-C и Objective-C ++ мы допускаем спецификатор
__weak
для__block
переменных типа объекта. [...] Этот определитель заставляет эти переменные сохраняться без сохранения отправляемых сообщений. Это сознательно приводит к оборванным указателям, если блок (или копия) переживает время жизни этого объекта.
Наконец, утверждение, что __block
может использоваться для исключения сильных ссылочных циклов (так называемых циклов сохранения), является неправильным в контексте ARC. В связи с тем фактом, что в ARC __block
заставляет переменную строго ссылаться, она, скорее всего, вызывает их.
Например, в MRC этот код прерывает цикл сохранения
__block typeof(self) blockSelf = self; //this would retain self in ARC!
[self methodThatTakesABlock:^ {
[blockSelf doSomething];
}];
тогда как для достижения такого же результата в ARC вы обычно делаете
__weak typeof(self) weakSelf = self;
[self methodThatTakesABlock:^ {
[weakSelf doSomething];
}];