Порядок инициализации и загрузки UIViewController - PullRequest
37 голосов
/ 13 января 2010

Я довольно новичок в программировании пользовательского интерфейса на Mac и iPhone, и я столкнулся с чем-то, что меня несколько озадачило.

UIViewController имеет 3 метода, которые включают его инициализацию и его представление:

  1. init (и init-подобные методы)
  2. loadView
  3. viewDidLoad (метод делегата)

Я ожидаю, что это произойдет в указанном выше порядке. Сначала UIViewController выделяется другим объектом, затем сразу вызывается init (или другой метод init, например initWithStyle).

Только после инициализации объекта я буду ожидать, что он вызовет собственную функцию loadView, после чего представление после загрузки вызывает метод делегата viewDidLoad.

Этого не происходит, например:

@implementation UIViewControllerSubclass

- (id)init {
        NSLog(@"0");
    if (self = [super init]) {
        NSLog(@"1");
    }
    return self;
}

- (void)loadView {
    [super loadView];
    NSLog(@"2");
}

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"3");
}

@end

Выводит консольный вывод:

0
2
3
1

Поэтому методы loadView и viewDidLoad не могут выполнять вызовы делегатов, поскольку делегат обычно устанавливается после вызова [super init], который (как показано выше) вызывается после loadView и viewDidLoad имеют бежать:

UIViewControllerSubClass *someViewController = [[UIViewControllerSubclass alloc] init];
[viewController setDelegate:self];

Если я хочу запустить код, который каким-то образом настраивает ViewController, уведомляя делегата о том, должен ли он находиться в методе init? Разве не существует причина, по которой loadView позволяет запускать такой код в нужный момент?

Мне кажется, мне придется создать новый метод initWithDelegate, который устанавливает делегат ivar до , вызывающий [super init], это правильно, или я поступаю неправильно?

Заранее спасибо:)

Ответы [ 5 ]

30 голосов
/ 13 января 2010

Система загрузки вида на iPhone работает следующим образом:

Когда вы инициализируете контроллер представления (с помощью -init или -initWithNibName: bundle :), он фактически не создает и не инициализирует представление. Когда вы вызываете -view в первый раз, он вызывает -loadView. По умолчанию -loadView просто загружает представление из файла xib (nibName). Если вы переопределите это, вы отвечаете за создание представления и его присвоение свойству view контроллера. Как пример:

- (void)loadView
{
   UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
   // add subviews 
   self.view = view;
   [view release];
}

Каждый раз, когда вы создаете представление, , которое отличается от того, как представление становится видимым и отображается на экране , вызывает -viewDidLoad. (-viewDidAppear / -viewDidDisappear предназначен для отображения видимости на экране)

Поскольку мы уже не в курсе, давайте рассмотрим управление памятью. Когда представление находится за пределами экрана, система автоматически установит для свойства представления контроллера представления значение nil. Проблема в том, что все подпредставления этого представления просочились. Как так? Ну, счетчик сохранения для каждого подпредставления равен 2 (представления сохраняют подпредставления, и у вашего контроллера представления есть выход / ivar). Когда представление равно nil, счетчик сохранения этого представления равен 1. Не имеет смысла для представления придерживаться, если представление не отображается, поэтому вы устанавливаете его равным nil в -viewDidUnload (который является ловушкой для всякий раз, когда вид установлен на ноль).

16 голосов
/ 13 января 2010

Метод initWithNibName: bundle: является назначенным инициализатором для класса UIViewController.

Попробуйте переопределить и использовать его вместо init:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
    }
    return self;
}

...

UIViewControllerSubClass *someViewController = [[UIViewControllerSubclass alloc] initWithNibName:@"UIViewControllerSubclass" bundle:nil];
13 голосов
/ 11 сентября 2013
-(void)awakeFromNib
{
}

вызывается, только если вы используете раскадровку для хранения нарисованного на раскадровке ViewController Nib --- означает пакет интерфейса.

правильная последовательность:

-(void)initWithCoder
-(void)awakefromNib    //(if story board is used)
    or
-(void)loadView----() //if manually generating the view contoller

-(void)viewDidLoad-----(called only once in the life cycle of viewController)
-(void)viewWillAppear
-(void)viewDidAppear

При переходе на новый ViewController

-(void)viewWillDisappear
-(void)viewDidDisappear

Возвращаясь к первому ViewController

-(void)viewWillAppear
-(void)viewDidAppear
4 голосов
/ 13 января 2010

Джерри3 прав. Этот материал все еще смущает меня тоже. Проверьте документы на обозначенные инициализаторы .

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

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

Но причина, по которой это выглядит не так, заключается в том, что [super init] вызывает loadView и т. Д. -

0 голосов
/ 10 июля 2012

Принимая предложение @ Nimrod, я сделал что-то вроде:

-(void)viewDidLoad
{
    // Init code here
}

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

просмотр жизненного цикла http://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/Art/loading_a_view_into_memory.jpg

Это взято из: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10-SW1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...