Почему делегатам Objective C обычно присваивается свойство, а не сохраняется? - PullRequest
175 голосов
/ 28 мая 2009

Я просматриваю замечательный блог, который ведет Скотт Стивенсон, и пытаюсь понять фундаментальную концепцию Objective-C, заключающуюся в назначении делегатам свойства 'assign' против 'retain'. Обратите внимание, что в среде сборки мусора они одинаковы. В основном меня интересует не основанная на GC среда (например, iPhone).

Непосредственно из блога Скотта:

"Ключевое слово assign создаст установщик, который присваивает значение переменной экземпляра напрямую, а не копирует или сохраняет его. Это лучше всего подходит для примитивных типов, таких как NSInteger и CGFloat, или для объектов, которыми вы непосредственно не владеете, таких как делегаты ".

Что это значит, что вы не являетесь непосредственным владельцем объекта делегата? Обычно я оставляю своих делегатов, потому что, если я не хочу, чтобы они уходили в пропасть, удержание позаботится об этом за меня. Я обычно абстрагирую UITableViewController от его соответствующего источника данных и делегирую также. Я также сохраняю этот конкретный объект. Я хочу убедиться, что он никогда не исчезнет, ​​поэтому у моего UITableView всегда есть свой делегат.

Может ли кто-нибудь дополнительно объяснить, где / почему я не прав, чтобы я мог понять эту общую парадигму в программировании Objective-C 2.0 использования свойства assign для делегатов вместо сохранения?

Спасибо!

Ответы [ 4 ]

175 голосов
/ 28 мая 2009

Причина, по которой вы избегаете сохранения делегатов, заключается в том, что вам нужно избегать цикла сохранения:

A создает B A устанавливает себя как делегат B ... A выпущен его владельцем

Если бы B сохранил A, A не был бы освобожден, так как B владеет A, таким образом, деаллок A никогда не был бы вызван, вызывая и A, и B .

Вам не стоит беспокоиться об уходе А, потому что он владеет Б и, таким образом, избавляется от него в dealloc.

44 голосов
/ 28 мая 2009

Поскольку объект, отправляющий сообщения делегата, не является владельцем делегата.

Во многих случаях все наоборот, например, когда контроллер устанавливает себя в качестве делегата представления или окна: контроллеру принадлежит представление / окно, поэтому, если представлению / окну принадлежит его делегат, оба объекта будут владеть друг с другом. Это, конечно, цикл сохранения, похожий на утечку с тем же следствием (объекты, которые должны быть мертвыми, остаются живыми).

В других случаях объекты являются равноправными: ни один не владеет другим, возможно, потому что они оба принадлежат одному и тому же третьему объекту.

В любом случае объект с делегатом не должен сохранять своего делегата.

(Кстати, есть, по крайней мере, одно исключение. Я не помню, что это было, и я не думаю, что для этого были веские причины.)


Приложение (добавлено 2012-05-19): в ARC вы должны использовать weak вместо assign. Слабые ссылки автоматически устанавливаются на nil, когда объект умирает, исключая возможность того, что делегирующий объект в конечном итоге отправит сообщения мертвому делегату.

Если по какой-то причине вы держитесь подальше от ARC, по крайней мере измените свойства assign, указывающие на объекты, на unsafe_unretained, которые явно указывают на то, что это необслуживаемая, но ненулевая ссылка на объект.

assign остается подходящим для необъектных значений как в ARC, так и в MRC.

17 голосов
/ 28 мая 2009

Обратите внимание, что когда у вас есть делегат, который назначен, очень важно всегда устанавливать значение этого делегата равным nil всякий раз, когда объект будет освобожден - поэтому объект всегда должен быть осторожен, чтобы исключить ссылки на делегаты в dealloc, если в другом месте этого не было.

1 голос
/ 28 декабря 2015

Одна из причин этого заключается в том, чтобы избегать сохранения циклов. Просто чтобы избежать сценария, когда A и B оба объекта ссылаются друг на друга, и ни один из них не освобождается из памяти.

На самом деле assign лучше всего подходит для примитивных типов, таких как NSInteger и CGFloat, или для объектов, которыми вы непосредственно не владеете, например, для делегатов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...