Какой инициализатор (ы) переопределить для подкласса UITableViewController

У меня есть подкласс UITableViewController, который создается в зависимости от того, где он используется, в NIB или через код. В обоих случаях я хочу выполнить настройку в методе инициализатора. Означает ли это, что мне нужно реализовать как initWithNibName:bundle: , так и initWithCoder:, и будет ли каждый метод вызывать соответствующий суперинициализатор?

Хотя сейчас мне это не нужно, но что, если я также хочу иметь возможность создать экземпляр контроллера представления с помощью initWithStyle:? Могу ли я тогда понадобиться 3 разных метода инициализации, которые воспроизводят одно и то же поведение?

Похоже, что это нарушает все обозначенное соглашение об инициализаторах, поскольку по существу будет 3 отдельных инициализатора, которые не вызывают общий метод инициализации. Или есть способ создать общий назначенный инициализатор при поддержке 3 разных маршрутов создания экземпляров?


person Daniel Dickison    schedule 13.04.2009    source источник


Ответы (5)


Мое замешательство было основано на ошибочном убеждении, что у каждого класса должен быть единственный назначенный инициализатор. Это неправда, и в случае UITableViewController есть 3 назначенных инициализатора (насколько я могу судить):

  1. initWithStyle: объявлен локально
  2. initWithNibName:bundle: унаследовано от UIViewController
  3. initWithCoder: от принятия NSCoding протокола

Вам необходимо переопределить 1 или более из них в вашем подклассе в зависимости от того, как создается экземпляр вашего подкласса. В моем случае мне пришлось реализовать № 2 и № 3, поскольку класс можно загрузить из NIB или создать экземпляр с помощью кода со ссылкой на NIB. (Я полагаю, что вы редко будете использовать и initWithStyle:, и initWithNibName:bundle: для одного класса.)

Я нашел Руководство по кодированию для Какао от Apple < / em> полезно.

person Daniel Dickison    schedule 16.04.2009
comment
Это не совсем так. - [UIViewController initWithCoder:], кажется, вызывает - [UIViewController initWithNibName: bundle:]. Нет необходимости отменять это. Следуйте совету КенниTM. - person fnf; 31.05.2013
comment
это точно. У меня ситуация, когда вызывается только initWithCoder. (У меня все 3 метода переопределены). - person Sam; 24.02.2014
comment
Что действительно сбивает с толку в iOS8, так это то, что initWithStyle: вызывает initWithNibName: bundle: и оба должны быть объявлены как назначенные инициализаторы. Это не соответствует правилам быстрого инициализатора. В iOS8, если вы не определите initWithNibName: bundle: и вызовете initWithStyle :, приложение выйдет из строя. Это было исправлено в iOS9. - person Gabriele Mondada; 04.12.2015

Внутри,

  • -initWithStyle: UITableViewController вызывает -init суперпользователя, а затем устанавливает _tableViewStyle ivar.
  • -init UIViewController просто вызывает -initWithNibName:bundle: с аргументами по умолчанию.
  • UITableViewController не переопределяет -initWithNibName:bundle:.

Следовательно, если вы переопределите -initWithNibName:bundle:, то -initWithStyle: тоже примет это изменение. Конечно, чтобы перестраховаться (так как не следует полагаться на детали реализации), переопределите их оба.

(И нет необходимости отменять -initWithCoder:, если только вы не разархивируете экземпляры.)

person kennytm    schedule 11.02.2010
comment
Переопределение -initWithNibName: bundle: само по себе должно быть безопасным, потому что на самом деле это не деталь реализации, а аспект фреймворка, в котором назначенные инициализаторы вызываются на всем протяжении цепочки наследования. И сама эта цепочка наследования является частью интерфейса UITableViewController. - person TBBle; 12.01.2011

Чтобы уточнить, initWithStyle:, единственный опубликованный инициализатор UITableViewController в документации, является его единственным явно назначенным инициализатором.

initWithNibName:bundle: наследуется от UIViewController и является назначенным инициализатором для этого класса. Таким образом, в соответствии с руководящими принципами Cocoa, UITableViewController должен переопределить этот метод (путем его реализации). Однако это не делает его назначенным инициализатором UITableViewController.

initWithCoder: - это, как вы указываете, неявный назначенный инициализатор из NSCoding.

person bfalling    schedule 10.02.2010

Воплощать в жизнь:

- (void) viewDidLoad

и выполните там инициализацию вашего компонента.

Его преимущество заключается в том, что инициализация выполняется только тогда, когда представление действительно запрашивается.

Или просто создайте отдельный метод настройки, вызываемый всеми инициализаторами.

person Kendall Helmstetter Gelner    schedule 13.04.2009
comment
Я не могу использовать viewDidLoad, потому что, в частности, мне нужно настроить self.navigationItem, который можно использовать до загрузки представления. Мог бы сделать отдельный метод настройки. Так неужели NSCoding по сути является исключением из правила единственного назначенного инициализатора? - person Daniel Dickison; 13.04.2009

Дополнение к сообщениям выше этой ссылки –initWithCoder:

Если вы добавили добавленный контроллер представления к его родительскому элементу через построитель интерфейса (например: если контроллер представления подключен к контроллеру панели вкладок в построителе интерфейса), вам необходимо переопределить –initWithCoder.

(-initWithNibName будет вызываться только при программном создании контроллера представления.)

person dana_a    schedule 03.01.2012