A Сохранение цикла происходит, когда два объекта хранят сильную ссылку друг на друга. Простейшим случаем является объект a
, хранящий значительную ссылку на объект b
и b
, выполняющий противоположное [1]. Сохранение циклов является проблемой в Objective-C, поскольку они заставляют ARC полагать, что эти объекты всегда используются, даже если эти объекты не упоминаются нигде.
Давайте рассмотрим несколько примеров. У вас есть объект z
, который выделяет a
и b
, использует их, а затем удаляет их.Если a
и b
создали цикл сохранения между собой, в первую очередь, a
и b
не будут освобождены. Если вы сделаете это несколько раз, вы будете серьезно утечка памяти.
Другой реальный мир пример сохранения цикла, если a
выделяет и сильно ссылается на b
объект, но вы также сохранить сильную ссылку из b
в a
(много мелких объектов в графе объектов может потребоваться доступ к своих родителей).
Наиболее обычным решением в этих случаях было бы убедиться, что содержащиеся в нем объекты имеют слабые ссылки на его содержащие объекты, а также убедитесь, что объекты-близнецы не содержат сильных ссылок друг на друга.
Другое решение (как правило, менее изящное, но возможно подходящее в некоторых ситуациях) может иметь какой-то пользовательский метод cleanup
в a
, который ссылается на b
. Таким образом, b
будет освобожден, если вызывается cleanup
(если b
не упоминается в другом месте). Это громоздко, потому что вы не можете сделать это с a
's dealloc
(он никогда не вызывается, если есть цикл сохранения), и потому что вы должны помнить, чтобы позвонить в cleanup
в соответствующее время.
- Следует отметить, что циклы сохраняют также транзитивно (например, объект
a
сильно ссылается b
, которые сильно ссылается c
, которые сильно ссылается a
).
Со всем этим сказал: управление памятью блоков довольно сложно понять.
Ваш первый пример может создать временный сохранить цикл (и только если self
объект сохраняет сильную ссылку на someObject
). Этот временной цикл уходит, когда блок завершает выполнение и освобождается.
Во время выполнения self
будет хранить ссылку на someObject
, someObject
к block
и block
к self
снова. Но опять же, это только временно, потому что блок не постоянно хранится где-либо (если это не делает реализация [someObject successBlock:failure:]
, но это не часто для блоков завершения).
Таким образом, цикл сохранения не является проблемой в вашем первом примере.
Как правило, удержание циклов внутри блоков является проблемой только в том случае, если какой-либо объект хранит блок, а не выполняет его непосредственно. Тогда легко увидеть, что self
сильно ссылается на block
, а block
имеет сильную ссылку на self
. Обратите внимание, что доступ к любому ivar изнутри блока автоматически генерирует сильную ссылку на self
в этом блоке.
Эквивалент тому, что содержащийся объект не ссылается на его контейнер, использует __weak SelfClass *weakSelf = self
для доступа к обоим методам и иварам (тем лучше, если вы получаете доступ к иврагам через аксессуры, как при использовании свойств).Ссылка вашего блока на self
будет слабой (это не копия, это слабая ссылка), и это позволит self
освободить, если она больше не ссылается на ссылки.
Можно утверждать, что это хорошая практика всегда использовать weakSelf
внутри всех блоков, сохраненных или нет, на всякий случай. Интересно, почему Apple не делала это по умолчанию. Выполнение этого обычно не делает ничего вредного для блочного кода, даже если оно фактически не используется.
__block
редко используется на переменные, которые указывают на объекты, так как Objective-C не обеспечивает неизменность объектов, как это.
Если у вас есть указатель на объект, вы можете вызвать его методы, и эти методы могут его модифицировать, с или без __block
. __block
больше (только?) Полезен для переменных основных типов (int, float и т. Д.). См. here, что происходит, когда вы используете __block
с переменной указателя объекта. Вы также можете узнать больше о __block
в Blocks Programming Topics от Apple.
Редактировать: Исправлена ошибка в отношении __block
Использование указателей объектов. Спасибо @KevinDiTraglia за указание на это.
Предполагая, что MyCLass реализует копию, которая является реальной копией ... потому что '-copyWithZone:' может просто сохранить ... что совершенно законно и сделано практически в любом неизменяемом объекте. –
@GradyPlayer: Возможно, я выразил себя плохо, но я имел в виду, что блок сохраняет сильный (или слабый) указатель в своем блочном контексте с текущим содержимым * 'self' (или' me'). Метод 'copy' * * не используется. –
Да, иногда SO циклирует материал назад, когда кто-то что-то делает с ними ... и иногда у меня должен быть nit-pick месяцев или лет спустя ... но объекты могут быть скопированы при захвате блоков, поэтому я не думаю, что это неверно ... –