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