Мне действительно интересно, хотя правила «не сохранять ваш делегат» по-прежнему применяются конкретно к многопоточным отношениям объект / делегат, особенно к тому, о котором вы пишете.Я нашел свой путь к этому вопросу, потому что я нахожусь в точно такой же ситуации: я выполняю асинхронную сетевую операцию конечной, но непредсказуемой длины (она завершится и завершится самостоятельно "в ближайшее время") в NSOperation и использует делегатхранится в NSOperation для уведомления о завершении операции обратно к исходному объекту-запросчику.
Сохранение делегата в этом случае имеет для меня смысл.В конце концов, операция завершится, она вызовет метод done для делегата, а затем освободит делегат и завершит свою работу.Если вызывающий объект был бы освобожден во время выполнения операции NSOperation, он просто задерживается немного дольше, пока операция не завершится.
Обратите внимание, что пометка свойства делегата атомарным, как предполагает drawonward, сама по себе недостаточна для защиты от условий гонки!Установка свойства как атомарного означает только то, что читатель или создатель свойства будет записывать или читать все целое значение за раз, ничего больше .Следующая последовательность может привести к сбою:
(поток NSOperation): NSOperation завершен и готовится уведомить объект делегата.Код атомарно считывает значение свойства делегата, готовящегося к вызову его метода done.
----> Поток переключается на основной
(основной поток), запрашивающий объект - dealloc 'd, а в -(void)dealloc
(атомарно!) устанавливается свойство делегата NSOperation равным nil, dealloc завершается, и объект теперь исчезает
-----> Переключение потока на поток NSOperation
(Поток NSOperation) вызывает [делегат allDone], и программа падает (если вам повезет), потому что объект делегата пропал.Если повезет.Возможно, что-то еще было выделено в этом пространстве тем временем, и теперь у вас непредсказуемая коррупция, что забавно!
Ключевым моментом здесь является то, что цикл сохранения является временным по самой своей природе -NSOperation завершит и очистит все самостоятельно.Это не то же самое, что UITextField и UIViewController, в которых хранятся сохраненные ссылки друг на друга, которые никогда не исчезнут и, таким образом, утечка памяти.
Мне кажется, что сохранение делегата в случае асинхронного, ограниченного, самостоятельногоЗавершение операции является самой чистой и надежной реализацией.
РЕДАКТИРОВАТЬ:
, если вам абсолютно не нужно сохранять делегат, потому что это вызывает проблемы с памятью, тогда вместо этого объект делегата и объект операции должны использовать обаявный механизм блокировки для синхронизации доступа к указателю делегата, сохраненному в операции.«атомарные» свойства действительно не обеспечивают потокобезопасный протокол для маркировки указателя делегата nil.
Но я думаю, что действительно усложняется и полон условий гонки.Я думаю, по крайней мере, что вы должны в dealloc объекта делегата запустить протокол блокировки, чтобы убедиться, что указатель делегата операции безопасно установлен равным nil, так что произвольное чередование потоков не может ни при каких обстоятельствах вызывать объект делегата dealloc'd.
Рабское следование правилам иногда делает вещи намного сложнее, чем они должны быть.Лучше понять, что такое правила, почему они существуют, и поэтому вы знаете, когда имеет смысл (как я полагаю, это имеет место в этом конкретном сценарии) не следовать им, и каковы преимущества / недостатки в этом.