Ответ 1
Нет. Проблема возникает, когда ваш блок сохраняет объект, который сохраняет его. Ваш блок сохранит любой объект, который он ссылается, кроме тех, которые были аннотированы с помощью __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
и прецедентом для слабых ссылок, прочитайте Избегайте сохранения циклов с блоками, правильный путь и ответ Джонатана Ренцша.