Использование метода с self внутри блоков

#objective-c #block #retain-cycle

#objective-c #блок #сохранение цикла

Вопрос:

Мне нужно выполнить один и тот же набор кода в двух блоках (я использую ARC):

 __weak typeof(self) weakSelf = self;
[_dataProvider doA:^(NSError *error) {
    [weakSelf handleError:error];
}];
  

И в другом месте я вызываю:

 __weak typeof(self) weakSelf = self;
[_dataProvider doB:^(NSError *error) {
    [weakSelf handleError:error];
}];
  

Тогда у меня есть мой обработчик:

 - (void)handleError:(NSError *)error {
    [self.refreshControl endRefreshing];
    [self.tableView reloadData];
}
  

Это сохранить, чтобы использовать его таким образом? Пожалуйста, обратите внимание, что handleError: метод использует self inside. Если нет, то каков здесь правильный подход? КСТАТИ: self является ViewController и может быть освобожден (doB: и doA: блоки основаны на сети, поэтому могут быть медленными).

Комментарии:

1. что вы имеете в виду, безопасно ли это использовать ? это не взорвет ваше устройство … так что, да, это безопасно с этой точки зрения.

2. это не «полностью» безопасно, см. Мой ответ.

Ответ №1:

Это небезопасно делать, даже если многие люди делают это так.

Вы должны использовать шаблон «weakSelf» с блоками, когда это оправдано. В вашем примере шаблон «weakSelf» не оправдан, потому self что не имеет никакой strong ссылки на ваш block . Вы можете использовать так :

 [_dataProvider doA:^(NSError *error) {
    // here you can use self, because you don't have any strong reference to your block

    [weakSelf handleError:error];
}];
  

Используйте шаблон «weakSelf», если у вас есть strong ссылка на ваш block (например, со свойством или переменной экземпляра), и вы записываете self внутри block , например :

  @property(strong) void(^)(void) completionBlock;
....

__weak typeof(self) weakSelf = self; 

    self.completionBlock = ^{
      // Don't use "self" here, it will be captured by the block and a retain cycle will be created
      // But if we use "weakSelf" here many times, it risques that it will be nil at the end of the block
      // You should create an othere strong reference to the "weakSelf"
      __strong typeof(self) strongSelf = weakSelf; 
      // here you use strongSelf ( and not "weakSelf" and especially not "self")
    };
  

Комментарии:

1. Я слышал что-то подобное. Однако xCode не согласен с этим, насколько я понимаю — [_someInstance doC:^(NSError *error) { self.index = 5; }]; (где @property (nonatomic, assign) NSInteger index; ). Претензии XCode Capturing 'self' strongly in this block is likely to lead to a retain cycle . У меня нет ни свойства, ни ivar для этого блока, почему я получаю предупреждение?

2. Я отключу предупреждение, выполнив: #pragma clang diagnostic push #pragma clang diagnostic игнорируется «-Warc-retain-cycles» …. ваш блок здесь #pragma clang diagnostic pop

3. Итак, вы утверждаете, что это общее предупреждение, и я не должен заботиться об этом в данном конкретном случае? Я обычно нахожу предупреждения полезными, и я боюсь, что за предупреждением скрывается какая-то «правда». Однако, если вы уверены, что в этом случае все в порядке, тогда я понимаю, как это работает.