Нет. Проблема возникает, когда ваш блок сохраняет объект, который сохраняет его. Ваш блок сохранит любой объект, на который он ссылается, кроме тех, которые отмечены __block
. Следовательно:
// The following creates a retain cycle which will leak `self`:
self.block = ^{
[self something];
};
self
сохраняет block
, а block
неявно сохраняет self
. Это также
произойдет, если вы ссылаетесь на переменные экземпляра self
.
// The following avoids this retain cycle:
__block typeof(self) bself = self;
self.block = ^{
[bself something];
};
Переменные, помеченные __block
, являются изменяемыми (для указателей, то есть
адрес, на который они указывают, может быть изменен); в результате нет смысла
сохранить этот объект, так как вам нужно рассматривать этот объект как локальную переменную
(как в случае, он может быть переназначен, затрагивая объект вне области блока). Таким образом, __block
не задерживается блоками.
Но теперь вы можете столкнуться с непредвиденными проблемами, если попытаетесь использовать этот блок определенным образом. Например, если вы решили каким-то образом отложить вызов этого блока, и self
был освобожден к моменту выполнения этого блока, ваша программа потерпит крах, так как вы отправляете сообщение освобожденному объекту. В таком случае вам нужна слабая ссылка, которая не предоставляется "из коробки" в среде без сбора мусора!
Одним из решений является использование MAZeroingWeakRef для упаковки вашего блока; это обнулит указатель, так что вы просто отправите сообщения на nil
, если попытаетесь отправить сообщение self
после освобождения self
:
MAZeroingWeakRef *ref = [MAZeroingWeakRef refWithTarget:self];
self.block = ^{
[ref.target something];
};
Я также реализовал оболочку слабых ссылок в Objective-C ++ , которая обеспечивает преимущество более легкого синтаксиса:
js::weak_ref<SomeClass> ref = self;
self.block = ^{
[ref something];
};
Поскольку js::weak_ref
является шаблоном класса, вы получите удобную строгую типизацию (то есть вы получите предупреждения во время компиляции, если попытаетесь отправить ссылке сообщение, на которое она не отвечает к). Но у Майка MAZeroingWeakReference
намного более зрелый, чем у меня, поэтому я советую использовать его, если вы не хотите испачкать руки.
Чтобы узнать больше о проблемах с __block
и сценарии использования для слабых ссылок, прочитайте Как избежать сохранения циклов с блоками, правильный путь и Ответ Джонатана Рентша .