Я пролистываю замечательный блог, который ведет Скотт Стивенсон, и пытаюсь понять фундаментальную концепцию Objective-C, заключающуюся в том, чтобы назначать делегатам свойство 'assign' против 'retain'. Обратите внимание, что в среде сборки мусора они одинаковы. В основном меня интересует не основанная на GC среда (например, iPhone).
Прямо из блога Скотта:
«Ключевое слово assign создаст установщик, который присваивает значение переменной экземпляра напрямую, а не копирует или сохраняет его. Это лучше всего подходит для примитивных типов, таких как NSInteger и CGFloat, или для объектов, которыми вы непосредственно не владеете, таких как делегаты».
Что это значит, что вы непосредственно не являетесь владельцем объекта делегата? Обычно я оставляю своих делегатов, потому что, если я не хочу, чтобы они уходили в пропасть, удержание позаботится об этом за меня. Я обычно абстрагирую UITableViewController от его соответствующего источника данных и делегирую также. Я также сохраняю этот конкретный объект. Я хочу убедиться, что он никогда не исчезнет, поэтому у моего UITableView всегда есть свой делегат.
Может кто-нибудь еще объяснить, где / почему я не прав, чтобы я мог понять эту общую парадигму в программировании Objective-C 2.0 использования свойства assign для делегатов вместо сохранения?
Спасибо!
источник
Ответы:
Причина, по которой вы избегаете сохранения делегатов, заключается в том, что вам нужно избегать цикла хранения:
A создает B A устанавливает себя в качестве делегата B ... A освобождается его владельцем
Если бы B сохранил A, A не был бы освобожден, так как B владеет A, таким образом, разлочка A никогда не была бы вызвана, вызывая утечку и A, и B.
Вам не стоит беспокоиться об уходе А, потому что он владеет Б и, таким образом, избавляется от него в dealloc.
источник
weak
не так? Вопрос в том, зачем использоватьassign
вместоweak
?assign
вместоretain
. Вопрос старше, чем ARC;weak
иstrong
(последний является синонимомretain
) не существовало до появления ARC. Вы должны задать свой вопрос оweak
противassign
отдельно.Поскольку объект, отправляющий сообщения делегата, не является владельцем делегата.
Много раз, наоборот, когда контроллер устанавливает себя в качестве делегата представления или окна: контроллеру принадлежит представление / окно, поэтому, если представлению / окну принадлежит его делегат, оба объекта будут принадлежать друг другу. Это, конечно, цикл сохранения, похожий на утечку с тем же следствием (объекты, которые должны быть мертвыми, остаются живыми).
В других случаях объекты являются равноправными: ни один не владеет другим, возможно, потому что они оба принадлежат одному и тому же третьему объекту.
В любом случае, объект с делегатом не должен сохранять своего делегата.
(Между прочим, есть по крайней мере одно исключение. Я не помню, что это было, и я не думаю, что для этого были веские причины.)
Приложение (добавлено 2012-05-19): в ARC вы должны использовать
weak
вместоassign
. Слабые ссылки устанавливаютсяnil
автоматически, когда объект умирает, исключая возможность того, что делегирующий объект в конечном итоге отправит сообщения мертвому делегату.Если по какой-то причине вы держитесь подальше от ARC, по крайней мере измените
assign
свойства, указывающие на объектыunsafe_unretained
, которые явно указывают на то , что это не сохраняемая, но ненулевая ссылка на объект.assign
остается подходящим для необъектных значений как в ARC, так и в MRC.источник
NSURLConnection
сохраняет свой делегат.weak
, но это не отвечает на первоначальный вопрос: почему Apple используетassign
вместоweak
?assign
а не сохраняются »;weak
не существовало, когда его спросили. Ваш вопрос другой, который вы должны задать отдельно. Я был бы рад ответить на это.Обратите внимание, что когда у вас есть делегат, который назначается, очень важно всегда устанавливать значение этого делегата равным nil всякий раз, когда объект будет освобожден - поэтому объект всегда должен быть осторожен, чтобы исключить ссылки на делегаты в dealloc, если он не имеет сделано в другом месте.
источник
Одна из причин этого заключается в том, чтобы избежать сохранения циклов. Просто чтобы избежать сценария, когда A и B оба объекта ссылаются друг на друга, и ни один из них не освобождается из памяти.
Оперативное назначение лучше всего подходит для примитивных типов, таких как NSInteger и CGFloat, или для объектов, которыми вы не владеете напрямую, таких как делегаты.
источник