Помните также, что циклы сохранения могут происходить, если ваш блок ссылается на другой объект, который затем сохраняет self
.
Я не уверен, что Сборка мусора может помочь в этих циклах сохранения. Если объект, сохраняющий блок (который я назову объектом сервера), переживет self
(объект клиента), ссылка наself
внутри блока не будет считаться циклической до тех пор, пока сам объект сохранения не будет освобожден. Если объект сервера далеко переживает своих клиентов, у вас может быть значительная утечка памяти.
Поскольку нет чистых решений, я бы порекомендовал следующие обходные пути. Не стесняйтесь выбирать один или несколько из них, чтобы решить вашу проблему.
- Используйте блоки только для завершения , а не для открытых событий. Например, используйте блоки для методов like
doSomethingAndWhenDoneExecuteThisBlock:
, а не методы like setNotificationHandlerBlock:
. Блоки, используемые для завершения, имеют определенный срок службы и должны быть освобождены объектами сервера после их оценки. Это предотвращает слишком длительный цикл сохранения, даже если он происходит.
- Сделайте тот слабый танец, который вы описали.
- Предоставьте метод для очистки вашего объекта перед его освобождением, который «отключает» объект от объектов сервера, которые могут содержать ссылки на него; и вызовите этот метод перед вызовом release объекта. Хотя этот метод вполне подходит, если у вашего объекта есть только один клиент (или он является единичным в некотором контексте), но он сломается, если у него несколько клиентов. Вы в основном побеждаете здесь механизм сохранения счета; это сродни звонку
dealloc
вместо release
.
Если вы пишете объект сервера, принимайте аргументы блока только для завершения. Не принимайте аргументы блока для обратных вызовов, таких как setEventHandlerBlock:
. Вместо этого вернитесь к классическому шаблону делегата: создайте формальный протокол и объявите setEventDelegate:
метод. Не оставляйте делегата. Если вы даже не хотите создавать формальный протокол, примите селектор в качестве делегата обратного вызова.
И наконец, эта схема должна вызывать сигналы тревоги:
- (void) dealloc {
[myServerObject releaseCallbackBlocksForObject: self];
...
}
Если вы пытаетесь отцепить блоки, которые могут ссылаться self
изнутри dealloc
, у вас уже есть проблемы. dealloc
никогда не может быть вызван из-за цикла сохранения, вызванного ссылками в блоке, что означает, что ваш объект будет просто утекать, пока объект сервера не будет освобожден.
self
доверенным лицам,this
просто чтобы перевернуть вещи. В JavaScript я называю своиthis
замыканияself
, так что это приятно и сбалансировано. :)