UIViewController, созданный с помощью initWithNibName: bundle: или через IBOutlet, ведет себя по-другому


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

В классе AppDelegate только что созданного проекта WindowBased я добавляю в окно UIViewController.
Я могу сделать это двумя разными способами:
- с IBOutlet. В IB я просто создал экземпляр UIViewController, установил его класс В TestViewController и подключил его (сценарий a кода).
- создание UIViewController с кодом (сценарий B).

    - (void)applicationDidFinishLaunching:(UIApplication *)application {    

#define USE_IBOUTLET YES // Comment this line to switch to scenario B

#ifdef USE_IBOUTLET
    // Scenario A

    [window addSubview:theTestViewController.view];
    [window makeKeyAndVisible];
#endif


#ifndef USE_IBOUTLET
    // Scenario B

    TestViewController *theTestViewControllerProgrammatically;

    theTestViewControllerProgrammatically = [[TestViewController alloc] initWithNibName:nil bundle:nil];

    // According to Apple: "It is a good idea to set the view's frame before adding it to a window.", so let's do it
    [theTestViewControllerProgrammatically.view setFrame:[[UIScreen mainScreen] applicationFrame]];

    [window addSubview:theTestViewControllerProgrammatically.view];

    [window makeKeyAndVisible];
#endif
}

Поскольку я не делал никаких настроек объекта в IB, я должен иметь одинаковое поведение в обоих сценариях.

Сценарий а, использование IBOutlet работает, как и ожидалось.
Но сценарий B имеет следующие проблемы:
- Вид находится не в правильном положении (20 пикселей в высоту, и покрыт строкой состояния).
- Вид не изменяется должным образом (например, попробуйте переключить в строке состояния вызова)

Почему?

Zip архив проекта здесь, Если вы хотите воспроизвести проблему: http://dl.dropbox.com/u/1899122/code/ProtoWindowBasedStrangeness.zip

3 3

3 ответа:

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

Эта строка:

[theTestViewController.view setFrame:[[UIScreen mainScreen] applicationFrame]];

На самом деле должно быть:

[theTestViewControllerProgrammaticaly setFrame:[[UIScreen mainScreen] applicationFrame]];

Вы устанавливали фрейм для VC, заданный IB, а не тем, который вы создали программно.

В любом случае-стоит отметить, что все мои комментарии по-прежнему применимы! Есть еще несколько вещей, которые вам придется делать программно, если вы не используете объекты контроллера IB (для пример, настройка элементов панели навигации)

Павел

У меня была очень похожая проблема с вами в том, что я заметил, что объекты VC не все созданы равными! Проблема в том, что я устанавливаю элементы панели навигации, я просто не могу этого сделать, когда владелец файла-объект контроллера вида, который я создаю программно. Это работает только в том случае, если я разархивирую объекты контроллера IB.

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

То, что я считаю, проблема состоит в том, что Apple создали эти объекты контроллера в ИБ, которые являются несколько более специализированных. Одно из предположений, что это может быть верно, состоит в том, что объекты IB VC имеют атрибут, который вы можете установить, который не имеет прямого соответствующего свойства для класса UIViewController, который я вижу, поэтому объекты контроллера IB могут иметь некоторые дополнительные функциональные возможности, которые подклассы UIViewController не могут использовать. от. Учитывая, что объекты в Ан .xib-это полные "сублимированные" объекты, Apple, возможно, включила все виды частных атрибутов, которые мы не можем видеть или использовать в их версиях IB - это может иметь некоторое влияние на то, как инициализируются объекты.

Например, в вашем MainWindow.xib, выберите объект IB VC, и вы можете установить атрибуты на нем из палитры инспектора, такие как"изменить размер представления из кончика". Если вы отмените эту проверку и повторно запустите приложение, вы увидите, что VC появляется точно так же, как и в сценарии B. Поскольку вы не можете проверить этот элемент, когда из атрибутов владельца файла (даже если это как UIViewController), вы не можете воспользоваться тем, что делается контроллером вида, чтобы дать вам желаемое поведение.

Результатом этого является то, что при использовании TestViewController.xib для инициализации объекта VC в коде не задается ни один из специфических атрибутов IB VC, поэтому создается стандартный UIViewController bog, и поэтому такие вещи, как атрибут "изменить размер представления из NIB" и настройка навигационные элементы должны быть реализованы самостоятельно.

Я еще не нашел способа воспользоваться функциональностью контроллеров представления IB, когда я создаю их с помощью initWithNibName:bundle:nibBundle (я предполагаю, что это все личные вещи, к которым мы не можем получить доступ), но надеюсь, что это могло бы дать вам отправную точку...

Конечно, я могу быть совершенно неправ, и кто-нибудь выставит меня полным идиотом!

Павел

Вероятно, в случае B это представление не знает о наличии строки состояния. Вам нужно изменить его размер соответствующим образом и настроить его положение, чтобы учесть строку состояния. Это делается путем изменения свойств фрейма (размер) и границ (расположение) UIView.