#iphone #ios #cocoa-touch #design-patterns #uiviewcontroller
#iPhone #iOS #cocoa-touch #шаблоны проектирования #uiviewcontroller
Вопрос:
Я задаю этот вопрос, потому что кажется, что viewDidLoad вызывается до того, как это делает основной блок инициализатора, а переменные класса, которые я инициализирую в инициализаторе, в viewDidLoad оказываются равными нулю. Для справки, я делаю весь этот viewcontroller программно, и я создал пользовательский инициализатор, чтобы я мог использовать различные параметры для использования в моем viewcontroller. Конечно, мой пользовательский инициализатор вызывает UIViewControllers, назначенный инициализатором.
В принципе, мне любопытно, каков правильный шаблон проектирования для отправки параметров в UIViewController? Я читал другие темы об этом и на самом деле не получил окончательного ответа. Должен ли я просто пропустить инициализатор и установить свойства вручную (из-за пределов класса)? Это кажется странным, я бы действительно хотел отправить некоторые параметры, и мне любопытно, как другие это делают?
Ответ №1:
Причина, по которой viewDidLoad вызывается до завершения инициализации, вероятно, заключается в том, что вы вызываете метод view в инициализаторе. Например:
- (id)init
{
if ((self = [super init])) {
_thing = 123;
_other = self.view.frame.size.width / 2;
}
return self;
}
viewDidLoad
вызывается при загрузке представления. И представление загружается, как только вы вызываете view
метод (или получаете доступ к свойству view, если хотите). Поэтому вам следует избегать ссылки на представление в init.
Чтобы ответить на ваш вопрос, я предпочитаю создать метод инициализации для своих контроллеров просмотра.
- (id)initWithThing:(MyThing *)thing thang:(MyThang *)thang
{
if ((self = [super init])) {
_thing = [thing retain];
_thang = [thang retain];
// ...
}
return self;
}
Вы также можете использовать свойства для установки дополнительных переменных после ввода. Лично я предпочитаю делать это только с необязательными свойствами и помещать требуемые свойства в метод init . Таким образом, я не могу инициализировать контроллер представления с недопустимым состоянием.
Ответ №2:
Я инкапсулирую состояние своих контроллеров в дополнительный объект состояния. Таким образом, контроллер обычно имеет ivar для элементов GUI и ссылку на этот объект состояния.
Объекты состояния обрабатываются объектом StateManager в моем делегате. Таким образом, вместо того, чтобы контроллер ссылался на другой контроллер и устанавливал переменные напрямую, все изменения проходят через этот менеджер. Немного больше работы, но менее грязно.
Любой класс может получить состояние для любого другого контроллера и изменить его. Это назначение некоторых контроллеров (например: выбор видео с YouTube происходит на выделенном контроллере). Но обычно только один класс получает состояние для отправки следующему контроллеру с помощью initWithState: . Затем перемещаемый контроллер применяет состояние к своему графическому интерфейсу в viewDidLoad или изменяет этот объект состояния, переданный из предыдущего класса.
StateManager хранит словарь всех объектов состояния. Я сохраняю отображение графика состояния объекта, например: я сохраняю ссылку на изображение, но не само изображение. Настоящая суть приложения находится в Core Data, я использую все это только для обработки состояния графического интерфейса. StateManager прослушивает событие выхода из приложения и сохраняет словарь состояния на диск, используя NSCoding. Ивары состояния объекта всегда равны нулю или некоторому значимому значению, без висячих указателей.
Я работаю над своим 2-м приложением для iPhone, и, похоже, это работает, но мне тоже интересно, как это делают другие люди. Приветствуется любой ввод.
Ответ №3:
В принципе, у вас должны быть свойства, определенные для ваших входных данных, но добавьте пользовательскую функцию инициализации.
Если вы создаете пользовательский метод инициализации, все должно быть в порядке — помните, что initWithNibName:bundle:
это основной инициализатор UIViewController
, так что это то, что вы хотите вызвать из своего пользовательского метода инициализации. viewDidLoad
всегда будет вызываться после вашего init-метода при первом использовании customVC.view
(либо из вашего кода, либо через фреймворк):
- (id)initWithDataObject:(MyDataObject*)obj
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
self.dataObj = obj;
}
return self;
}