ViewDidLoad и awakeFromNib

Я понимаю, что awakeFromNib всегда будет вызываться перед viewDidLoad.

Итак, у меня есть подкласс UITableViewController, который не имеет аналогов из файла xib.

Я определил эти два метода внутри:

- (void)awakeFromNib {
  [super awakeFromNib];
  NSLog(@"awake from nib");
}

- (void)viewDidLoad {
  [super viewDidLoad];
  NSLog(@"view did load");
}

происходит то, что "view did load" появляется до "awake from nib" в консоли. Я попытался использовать точку останова на [super awakeFromNib] и многократно нажимал F7 (Step Into), и, к моему удивлению, он вступил в (void) viewDidLoad ПЕРЕД ПЕРЕД прохождением ко второй строке в awakeFromNib.

Кто-нибудь знает, что здесь происходит? Я сделал то же самое в подклассе обычного UIViewController, и операторы журнала меняются на противоположные, как я и ожидал...

Ответ 1

Чтобы понять этот факт, я рекомендую вам loadNibNamed:owner:options: метод NSBundle.

Когда вы запускаете контроллер вида из nib, в первую очередь он загружает просмотры, которые там содержатся, то он устанавливает свойства файлов в соответствии с nib. Метод viewDidLoad вызывается, когда он устанавливает свойство владельца файла view в одно из видов, которые были загружены. И awakeFromNib вызывается, когда установлены все фиды и свойства файлов (включая свойство view). Поэтому имеет смысл, что viewDidLoad вызывается раньше awakeFromNib.

Надеюсь, что это поможет

Ответ 2

Я создаю тестовый проект с опцией Приложения на основе навигации и добавляю следующие коды в rootViewController.m.

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

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

Затем я получил результаты из консоли:

awakeFromNib 1
awakeFromNib 2
viewDidLoad 1
viewDidLoad 2

-(void)viewDidLoad будет вызываться при загрузке представления контроллера. Таким образом, когда вы впервые используете self.view =..., будет вызываться -(void)viewDidLoad.


Если вы написали что-то вроде следующего, тогда -(void)viewDidLoad будет вызван первым.

  - (void)awakeFromNib {
       NSLog(@"awakeFromNib 1");

       // The log sequence will be funny, if 'viewDidLoad' raised before [super awakeFromNib]
       // If you are curios about it, just give it a try.           
       // self.view.backgroundColor = [UIColor clearColor];

       [super awakeFromNib];

       /// viewDidLoad will be called 
       /// because self.view must be loaded first.
       self.view.backgroundColor = [UIColor clearColor];  

       NSLog(@"awakeFromNib 2");
  }

и получить следующие результаты.

awakeFromNib 1
viewDidLoad 1
viewDidLoad 2
awakeFromNib 2

Обновить

loadViewIfNeeded вызовет viewDidLoad если загрузит представление успешно. Иногда я буду вызывать loadViewIfNeeded, чтобы убедиться, что экземпляры @IBOutlet были инициализированы и больше не @IBOutlet нулю.

Ответ 3

Я не думаю, что вам нужно вызвать awakeFromNib в своем суперклассе.

Отметьте этот.

Edit

Я только что проверил быстрый тест, вот результаты:

Сценарий 1: MainWindow.Xib имеет подкласс UIViewController TestingAwakeFromNibViewController, у которого есть собственный файл Nib TestingAwakeFromNibViewController.xib.

TestingAwakeFromNibViewController имеет выход UIButton, называемый btn3. Тестирование следующего кода:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog(@"Btn3 %@",btn3);

    NSLog(@"viewDidLoad");
}


-(void) awakeFromNib
{
    [super awakeFromNib];

    NSLog(@"Btn3 %@",btn3);

    NSLog(@"awakeFromNib");
}

Будет печать:

Btn3 (null)
AwakeFromNib
Btn3 <UIRoundedRectButton: 0x64088e0; frame = (114 211; 72 37); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x6408890>>
ViewDidLoad

Сценарий 2: Удаление xib файла, добавление UIView в качестве сына в TestingAwakeFromNibViewController внутри MainWindow.Xib и добавление UIButton в качестве подпрограммы UIView (и подключение выхода UIbutton к соответствующему выходу TestingAwakeFromNibViewController).

Теперь выполняемый выше код будет печатать:

Btn3 <UIRoundedRectButton: 0x4e31c30; frame = (114 211; 72 37); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x4e31be0>>
viewDidLoad
Btn3 <UIRoundedRectButton: 0x4e31c30; frame = (114 211; 72 37); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x4e31be0>>
awakeFromNib

Значение ViewDidLoad до AwakeFromNib.

Третий сценарий: То же, что и второе, без вызова [super awakeFromNib];

Btn3 <UIRoundedRectButton: 0x4e0ddf0; frame = (114 211; 72 37); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x4e0dda0>>
awakeFromNib

Теперь ViewDidLoad даже не вызван.

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

Ответ 4

Не будучи экспертом и следуя этим сообщениям, я понимаю, чем в сценарии с контроллером табуляции. В "дочернем" контроллере представлений метод awakeFromNib выполняется при загрузке контроллера табуляции (родителя), но viewDidLoad только тогда, когда его "Tab".

И поэтому я понимаю, что это можно использовать для загрузки данных только тогда, когда выбрана конкретная вкладка (нажата)