Пам'ятайте також, що цикли збереження можуть відбуватися, якщо ваш блок посилається на інший об'єкт, який потім зберігає self
.
Я не впевнений, що збір сміття може допомогти у цих циклах утримання. Якщо об’єкт, що зберігає блок (який я буду називати об’єктом сервера), застарілий self
(клієнтський об'єкт), посилання на self
блок всередині блоку не вважатиметься циклічним, поки сам звільняючий об'єкт не буде звільнений. Якщо серверний об’єкт сильно пережив своїх клієнтів, у вас може виникнути значна витік пам'яті.
Оскільки чистих рішень немає, я б рекомендував наступні способи вирішення. Ви можете вибрати один або декілька з них, щоб вирішити свою проблему.
- Використовуйте блоки лише для завершення , а не для відкритих подій. Наприклад, використовувати блоки для таких методів
doSomethingAndWhenDoneExecuteThisBlock:
, а не таких методів setNotificationHandlerBlock:
. Блоки, які використовуються для завершення, мають певний термін служби, і їх слід випускати об’єктами сервера після їх оцінки. Це заважає циклу утримування жити занадто довго, навіть якщо він стався.
- Зробіть той слабкий еталонний танець, який ви описали.
- Надайте спосіб очищення вашого об'єкта до його випуску, який "відключає" об'єкт від серверних об'єктів, які можуть містити посилання на нього; і викликати цей метод перед тим, як викликати випуск на об'єкт Хоча цей метод є прекрасним, якщо у вашого об’єкта є лише один клієнт (або він є однотонним у певному контексті), але він руйнується, якщо у нього є кілька клієнтів. Ви в основному переможете тут механізм підрахунку утримування; це схоже на дзвінки
dealloc
замість release
.
Якщо ви пишете серверний об’єкт, приймайте блок-аргументи лише для його завершення. Не приймайте блокові аргументи для зворотних викликів, наприклад setEventHandlerBlock:
. Натомість поверніться до класичного шаблону делегата: створіть офіційний протокол та рекламуйте setEventDelegate:
метод. Не утримуйте делегата. Якщо ви навіть не хочете створити офіційний протокол, прийміть селектор як зворотний зворот делегата.
І нарешті, ця модель повинна звучати тривожно:
- (недійсна) угода {
[myServerObject releaseCallbackBlocksForObject: self];
...
}
Якщо ви намагаєтесь зняти блоки, які можуть посилатися self
зсередини dealloc
, у вас вже виникають проблеми. dealloc
може ніколи не викликатися через цикл утримування, викликаний посиланнями в блоці, а це означає, що ваш об'єкт просто просочиться, поки серверний об’єкт не буде розміщений.
self
проксі,this
щоб просто перевернути речі. У JavaScript я називаю своєthis
закриттяself
, тому він відчуває себе приємно і врівноважено. :)