Возможно передать [self anyFunction] в блоках без __weak объекта (iOS 5 + ARC)
Можно ли передать [self anyFunction] в блоки без __weak-объекта от self?
В качестве примера это допустимый код из System Framework:
[UIView animateWithDuration:0.8 animations:^{
//Do animationStuff
} completion:^(BOOL finished) {
[self anyFunction];
}];
Вы можете пройти [self anyFunction]
в блоке завершения без предупреждения. Но если вы напишите свой собственный метод с блоком завершения, появится следующее предупреждение: сильный захват "себя" в этом блоке может привести к циклу сохранения.
Рабочее решение довольно простое (iOS 5 + ARC). Перед тем как объявить блок:
__weak MyClass *weakSelf = self;
и в блоке завершения вы должны позвонить:
[weakSelf anyFunction];
Но вернемся к моему вопросу: почему API-интерфейсам System Framework нет необходимости использовать __weak
объект и использовать self
без каких-либо предупреждений. И как реализовать метод без необходимости __weak
объект в блоке?
Спасибо за ваши усилия.
2 ответа
Блоки, которые выдают ошибку, являются теми, где вы захватываете объекты, которые владеют блоком. Например
[object performBlock:^{
[object performSomeAction]; // Will raise a warning
}];
или же
[self performBlock:^{
[self doSomething]; // Will raise a warning
}];
но
[self performBlock:^{
[object doSomething]; // <-- No problem here
}];
Потому что объект сохраняет свои блоки, а блок сохраняет свои объекты. Таким образом, в обоих этих случаях объект, который выполняет блок, владеет блоком, который также владеет объектом. Итак, у вас есть цикл - цикл сохранения. что означает, что память просочилась.
В приведенном вами примере - вы смотрите на метод класса. Вы вызываете блок на UIView
класс, а не UIView
объект. У класса нет памяти, связанной с ним. И вы, вероятно, вызываете эту функцию из контроллера, поэтому self
ссылка сохраняется блоком, но цикл отсутствует, потому что self не сохраняет блок.
Точно так же, как вы, наверное, заметили, не все объекты, используемые в блоке, должны иметь слабую ссылку - только те, которые вызывают цикл сохранения.
В коде, который мне нужно скомпилировать потенциально или без ARC, или с новыми компиляторами или без них, я делаю следующее... функционально это то же самое, что вы уже перечислили, но избегает __weak и также избегает сохраняемого выпуска циклы:
//
// FOR NON-ARC PROJECTS
//
__block __typeof__(self) bself = self;
[someObject doThingWithBlock:^(id result){
if (!bself)
return;
bself.thingWhich = result;
}];
///
// FOR ARC PROJECTS
//
__weak MyClass *bself = self;
[someObject doThingWithBlock:^(id result){
if (!bself)
return;
bself.thingWhich = result;
}];