Сильный захват "себя" в этом блоке может привести к сохранению цикла
У меня есть запрос с блоком. Но компилятор выдает предупреждение
"Сильный захват" себя "в этом блоке может привести к сохранению цикла"
__weak typeof(self) weakSelf = self;
[generalInstaImage setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:data[@"images"][@"low_resolution"][@"url"]]] placeholderImage:[UIImage imageNamed:@"Default"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
NSLog(@"success");
[generalInstaImage setImage: image];
[weakSelf saveImage:generalInstaImage.image withName:data[@"id"]];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(@"fail");
}];
Я попробую пример напиши как weakSelf.generalInstaImage
, но затем компилятор генерирует ошибку и не компилируется.
2 ответа
Учтите это предупреждение:
Захватив
self
сильно в этом блоке, вероятно, приведет к сохранению цикла
Когда вы получите вышеупомянутое предупреждение, вы должны проверить свой блок на:
- любые явные ссылки на
self
; или же - любые неявные ссылки на
self
вызвано ссылками на любые переменные экземпляра.
Давайте представим, что у нас есть какое-то простое свойство класса, которое было блоком (в нем будут появляться те же предупреждения о "цикле сохранения", что и в вашем вопросе, но мои примеры будут немного проще):
@property (nonatomic, copy) void (^block)(void);
И давайте предположим, что у нас есть другое свойство класса, которое мы хотели использовать внутри нашего блока:
@property (nonatomic, strong) NSString *someString;
Если вы ссылаетесь self
в блоке (в моем примере ниже, в процессе доступа к этому свойству) вы, очевидно, получите это предупреждение о риске сохранения цикла:
self.block = ^{
NSLog(@"%@", self.someString);
};
Это исправляется с помощью предложенного вами шаблона, а именно:
__weak typeof(self) weakSelf = self;
self.block = ^{
NSLog(@"%@", weakSelf.someString);
};
Менее очевидно, вы также получите предупреждение "сохранить цикл", если вы ссылаетесь на переменную экземпляра класса внутри блока, например:
self.block = ^{
NSLog(@"%@", _someString);
};
Это потому что _someString
переменная экземпляра содержит неявную ссылку на self
и на самом деле эквивалентно:
self.block = ^{
NSLog(@"%@", self->_someString);
};
Вы можете быть склонны попытаться принять здесь также слабую модель себя, но вы не можете. Если вы попытаетесь weakSelf->_someString
Синтаксический шаблон, компилятор предупредит вас об этом:
Разыменование
__weak
указатель недопустим из-за возможного нулевого значения, вызванного условием гонки, присвойте егоstrong
переменная первая
Поэтому вы решаете это с помощью weakSelf
шаблон, но и создать местный strong
переменную внутри блока и использовать ее для разыменования переменной экземпляра:
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(self) strongSelf = weakSelf;
if (strongSelf) {
NSLog(@"%@", strongSelf->_someString);
// or better, just use the property
//
// NSLog(@"%@", strongSelf.someString);
}
};
Кроме того, это создание местного strong
ссылка, strongSelf
внутри блока есть и другие преимущества, а именно: если блок завершения работает асинхронно в другом потоке, вам не нужно беспокоиться о self
освобождение во время выполнения блока, что приводит к непредвиденным последствиям.
это weakSelf
/ strongSelf
шаблон очень полезен, когда имеешь дело со свойствами блока, и ты хочешь предотвратить сохранение циклов (или сильных эталонных циклов), но в то же время гарантируя, что self
не может быть освобожден в середине выполнения блока завершения.
К вашему сведению, Apple обсуждает этот шаблон в обсуждении "нетривиальных циклов" далее в разделе " Использование квалификаторов на протяжении всей жизни для избежания сильных эталонных циклов " в примечаниях к выпуску " Переход к ARC".
Вы сообщаете, что получили какую-то "ошибку", когда ссылались weakSelf.generalInstaImage
в вашем примере. Это правильный способ устранения этого предупреждения "сохранить цикл", поэтому, если вы получили какое-то предупреждение, вы должны поделиться им с нами, а также показать нам, как вы объявили свойство.
Использование __unsafe_unretained typeof(self) weakSelf = self