Подтвердить что ты не робот

Корректная реализация loadView

Документы Apple не говорят, какая правильная реализация для loadView.

Я обнаружил, что если вы реализуете loadView следующим образом:

- (void)loadView
{
    self.view = [[UIView alloc] init];
}

... тогда вы получите другое поведение, чем если бы вы его вообще не реализовали. В частности, в одном проекте из 20 строк я обнаружил, что viewWillAppear вызывается с фреймом нулевого размера для self.view - если вы не используете версию LoadView по умолчанию Apple по умолчанию.

Глядя на Google, существует множество "обучающих программ", которые обеспечивают явно неправильные реализации loadView - например, force-setting size (320,480), потому что автор учебника "обнаружил, что он работает, если я это делаю".

Я хотел бы знать, какова должна быть правильная реализация.

NB: в моем примере выше я добавляю его в иерархию представлений внутри AppDelegate следующим образом:

[self.window addSubview:(UIViewController*).view];

Я считаю, что в присутствии UINavigationController или UITabBarController Apple делает некоторую дополнительную магию, которая - как побочный эффект - заставляет однострочную реализацию loadView работать нормально. Но я хочу написать это правильно, чтобы он всегда работает!

NB: я попытался установить маску авторезиста в корневом представлении, но это не меняет того, что происходит:

- (void)loadView
{
    self.view = [[UIView alloc] init];
    self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
4b9b3361

Ответ 1

Реализация по умолчанию -loadView создает представление или загружает NIB. Насколько мне известно, нет способа узнать конечный размер представления в момент создания в -loadView. Таким образом, размер представления по умолчанию установлен на [[UIScreen mainScreen] bounds]. Это связано с тем, что работать с представлением нулевого кадра в -viewDidLoad и другими методами может быть сложно.

Ваша однострочная реализация может выглядеть так:

- (void)loadView {
    self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
}

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

Представьте это в методе UINavigationController:

// we are pushing new VC, view is accessed for the first time
pushedVC.view.frame = CGRectMake(...);

Он устанавливает правильный фрейм, но ваш -loadView вызывается только до, который -setFrame:. Таким образом, во время -viewDidLoad у вас есть временный ненулевой фрейм, чтобы иметь возможность настраивать subviews и внутреннюю автореализацию. После этого правильный фрейм установлен для вас, а в -viewWillAppear: у вас есть окончательный кадр.

Ответ 2

Во-первых, нет реализации по умолчанию loadView... этот метод специально предназначен для вас. Я согласен с тем, что документы Apple могут быть немного неясными. Но loadView вызывается по умолчанию всякий раз, когда открывается доступ к просмотру навигационного контроллера, и нет представления (например: UIView *view = viewController.view). Его также можно вызвать вручную. Но ни в коем случае loadView не имеют правильных размеров... то есть, по сути, невозможно. loadView вызывается для того, чтобы контроллер родительского представления получил представление в первую очередь, чтобы он мог соответствующим образом изменить его. Затем, получив представление, он вызывает viewDidLoad. Это единственный путь к коду, который они могут использовать, поскольку представления могут загружаться из метода loadView или nib, и они должны предоставить место для дополнительной настройки, когда представления загружаются из наконечника. Наконец, родительский контроллер изменит размер представления и вызовет viewWillAppear только тогда, когда представление действительно появится. Например, если вы нажмете контроллер на navController, который выключен, он не вызовет viewWillAppear, пока сам navController не будет помещен на экран. Это делается потому, что нет смысла запускать этот код, пока контроллер не будет виден. Именно поэтому вы можете получить только правильное измерение в методе viewWillAppear.

Теперь вы заметили, что если вы добавите контроллер в стандартный контроллер, ничего из этого не произойдет. Это связано с тем, что диспетчеры представления на самом деле не предназначены для размещения других контроллеров представлений для каждого сообщения. Теперь в iOS 5 они явно поддерживают использование Container View Controllers... который по существу является контроллером представления, который предназначен для размещения других контроллеров представлений. Они добавили несколько "удобных" методов в iOS 5, чтобы помочь в этом, но это не является строго необходимым. Суть всего этого заключается в следующем: если вы хотите добавить один контроллер просмотра в другой, вам придется вручную настроить все соответствующие вызовы на контроллер дочернего представления (все методы загрузки, события поворота, предупреждение о памяти и т.д.). Другими словами, вы должны создать свой собственный контроллер контейнера. Однако, когда вы это делаете, имейте в виду, что я сказал раньше о пути кода. Важно, чтобы вы называли методы контроллера дочерних элементов в том же порядке, что и Apple, или вещи не будут работать правильно.

Вот некоторые ссылки на информацию: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html -Свернуть вниз: Реализация контроллера просмотра контейнера

Также здесь для жизненного цикла контроллера просмотра, который поможет вам определить, какие вызовы необходимо выполнить в каком порядке: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10-SW1

Я действительно рекомендую прочитать весь Руководство по программированию на View Controller.... вы можете получить оттуда много информации: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007457-CH1-SW1