2010-01-13 2 views
35

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

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 метод, который устанавливает делегат Ивар перед тем вызывающего [супер INIT], это правильно, или я буду об этом не так?

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

ответ

30

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

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

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

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

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

+2

Примечание: viewDidUnload устарел с iOS 6.0. – Brainware

16

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

Try наиважнейшая и использовать его вместо инициализации:

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

...

UIViewControllerSubClass *someViewController = [[UIViewControllerSubclass alloc] initWithNibName:@"UIViewControllerSubclass" bundle:nil]; 
+1

Hm .. Когда я пытаюсь запустить его в 5.1. Симулятор, отладчик не достигает ни одного: - [MyViewController initWithNibName: bundle:] 'или' - [MyViewController init] ' –

+0

Здесь вы инициализируете UIViewController, как таковой, но ** не **, где вы обманываете представление. – Fattie

4

gerry3 прав. Этот материал все еще меня смущает. Проверьте документы на designated initializers.

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

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

Но причина этого, кажется, из того, что [супер INIT] звонит loadView и т.д. -

+0

«Большая часть кода, который я видел, выполняет большинство инициализации в таких вещах, как viewDidLoad, хотя это кажется неправильным». На самом деле это ошибка. Причиной этого является то, что ваше представление может быть выгружено, пока ваш контроллер просмотра все равно будет готов, готов снова загрузить представление по требованию. Поэтому вы рискуете повторно инициализировать свои переменные, а в некоторых случаях это может привести к жестким логическим проблемам в вашем приложении. – KPM

0

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

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

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

view lifecycle 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

12
-(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 
+0

loadView также вызывается, если используется панель рассказов – malhal

Смежные вопросы