Подтвердить что ты не робот

Захват "я" сильно в этом блоке, вероятно, приведет к циклу сохранения

Я требую блока. Но компилятор выдает предупреждение

"Захват" я "сильно в этом блоке, скорее всего, приведет к сохранению Цикл"

__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, но тогда компилятор генерирует ошибку и не компилируется.

4b9b3361

Ответ 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 в вашем примере. Это правильный способ разрешения этого предупреждения "сохранить цикл", поэтому, если вы получили какое-то предупреждение, вы должны поделиться этим с нами, а также показать нам, как вы объявили свойство.

Ответ 2

Используйте __unsafe_unretained typeof(self) weakSelf = self