Ответ 1
Рассмотрим это предупреждение:
Захват
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
не может быть освобожден в середине выполнения блока завершения.
FYI, Apple обсуждает этот шаблон в обсуждении "нетривиальных циклов" ниже в использовать пожизненные квалификаторы, чтобы избежать сильных ссылочных циклов раздел примечаний о выпуске Transitioning to ARC.
Сообщаете, что вы получили некоторую "ошибку", когда вы ссылались на weakSelf.generalInstaImage
в вашем примере. Это правильный способ разрешения этого предупреждения "сохранить цикл", поэтому, если вы получили какое-то предупреждение, вы должны поделиться этим с нами, а также показать нам, как вы объявили свойство.