Каков наилучший способ отправки параметров в UIViewController?

#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;
}