2013-10-07 4 views
23

Я прочитал эту тему: What does the "__block" keyword mean?, где обсуждается, что используется __block, но я смущен одним из ответов. Он говорит, что __block используется, чтобы избежать циклов сохранения, но комментарии под ним оставляют меня неуверенными.Использование __block и __weak

Я использую это что-то вроде этого:

self.someProperty = x; //where x is some object (id) 
__block __weak VP_User *this = self; 

//begin a callback-style block 
    this.someProperty = nil; 

мне нужно использовать как __block и __weak ли? Какие-то вопиющие проблемы с этим выглядит?

+0

Нет это, вероятно, говорит «' __weak' используется для избегайте удерживать циклы ». – trojanfoe

+0

На самом деле один из ответов (подтвержденный, но не принимаемый) говорит: «' __block' иногда используется, чтобы избежать циклов сохранения » – Adam

+0

Я этого не понимаю; использование '__weak' - это способ избежать этого. – trojanfoe

ответ

57

__block является классификатором хранения. Он указывает, что переменная должна быть непосредственно захвачена блоком, а не копированием. Это полезно в случае, если вам необходимо изменить исходную переменную, как показано в следующем примере

__block NSString *aString = @"Hey!"; 
void(^aBlock)() = ^{ aString = @"Hello!" }; // without __block you couldn't modify aString 
NSLog(@"%@", aString); // Hey! 
aBlock(); 
NSLog(@"%@", aString); // Hello! 

В АРК это вызывает переменная будет автоматически сохранена, так что его можно смело ссылаться в рамках реализации блока. В предыдущем примере затем 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]; 
}]; 

а для достижения такого же результата в АРК, обычно не делают

__weak typeof(self) weakSelf = self; 
[self methodThatTakesABlock:^ { 
    [weakSelf doSomething]; 
}]; 
+0

Итак, если я читаю это правильно, не имеет смысла использовать __block и __weak вместе, потому что они фактически делают противоположные вещи (в ARC)? – Adam

+3

Нет. Это может иметь смысл, если вы хотите изменить объект внутри блока, но сохранение ссылки на него вызовет цикл сохранения. Я не могу придумать хороший пример, но может существовать законное использование. Вот почему это разрешено, хотя и потенциально опасно, как отмечается в документации. –

+0

«В ARC это приводит к автоматическому сохранению переменной» Как работает сохранение переменной? «Переменная», которая должна быть доступна, является указателем '* aString', а не объектом. Как вы сохраняете указатель? –

13

Вы должны использовать __block, если вы хотите изменить значение переменной в блоке.

например:

__block BOOL result = NO; 
dispatch_sync(dispatch_get_main_queue(), ^{ 
    ... 
    result = YES; 
    ... 
}); 

Вы должны использовать __weak, если вы хотите, чтобы избежать сохранения циклов.

.: например

__weak typeof(self) wself = self; 
self.foobarCompletion = ^{ 
    ... 
    wself.foo = YES; 
    ... 
}; 

Вы можете комбинировать их, если есть необходимость.

+0

Простые и полезные примеры, спасибо! –

Смежные вопросы