iPhone SDK: qual é a diferença entre loadView e viewDidLoad?

136

Ao trabalhar com visualizações e visualizadores de controladores em um aplicativo para iPhone, alguém pode explicar a diferença entre loadView e viewDidLoad?

Meu contexto pessoal é que eu construo todas as minhas visualizações a partir do código, não uso e não utilizarei o Interface Builder, caso isso faça alguma diferença.

Descobri que, muitas vezes, quando adiciono o código init ao loadView, acabo com um rastreamento de pilha infinito; portanto, normalmente faço toda a construção de exibição de filhos em viewDidLoad ... mas não é realmente claro para mim quando cada um é executado, e qual é o local mais apropriado para colocar o código init. O que seria perfeito, é um diagrama simples das chamadas de inicialização.

Obrigado!

ryan.scott
fonte

Respostas:

200

Eu posso adivinhar qual pode ser o problema aqui, porque eu fiz isso:

Descobri que, frequentemente, quando adiciono o código init ao loadView, acabo com um rastreamento de pilha infinito

Não leia self.view em -loadView. Apenas defina , não entenda .

O acessador da propriedade self.view chama -loadView se a visualização não estiver carregada no momento. Aí está sua recursão infinita.

A maneira usual de criar a exibição programaticamente no -loadView, como demonstrado nos exemplos pré-construtores de interface da Apple, é mais ou menos assim:

UIView *view = [[UIView alloc] init...];
...
[view addSubview:whatever];
[view addSubview:whatever2];
...
self.view = view;
[view release];

E eu não culpo você por não usar o IB. Eu segui esse método para todo o Instapaper e me sinto muito mais confortável com ele do que lidar com as complexidades do IB, peculiaridades da interface e comportamento inesperado nos bastidores.

Marco
fonte
ahhhh, obrigado por uma explicação, finalmente! Evitei o idioma de alocar uma variável temporária, defini-lo como self.view e liberar ... parecia algo estranho, desnecessário. Agora posso entender por que essa decisão me levaria ao caminho em que agora me encontro.
Ryan.scott #
Eu tenho esse código e não há recursão. porque? -(void) loadView { // Frame for Hypnosis view CGRect frame = [[UIScreen mainScreen] bounds]; // Create a Hipnosis view v = [[HypnosisView alloc] initWithFrame:frame]; self.view = v;
user2054339
44

loadViewé o método em UIViewControllerque realmente carregará a exibição e a atribuirá à viewpropriedade Esse também é o local que uma subclasse UIViewControllersubstituirá se você desejar configurar programaticamente a viewpropriedade.

viewDidLoadé o método chamado após o carregamento da visualização. Isso é chamado depois que o loadView é chamado. É um local onde você pode substituir e inserir o código que faz a configuração inicial adicional da visualização depois que ela é carregada.

NilObject
fonte
14
viewDidLoad()

deve ser usado quando você carrega sua visualização de um NIB e deseja executar qualquer personalização após o lançamento

LoadView()

deve ser usado quando você deseja criar sua exibição programaticamente (sem o uso do Interface Builder)

ashokdy
fonte
Isso pode ter algum problema, eu tenho teste quando meu controlador de vista não foi associado com o arquivo NIB, viewDidLoad ainda chamava
ruandao
11

Apenas adicionando alguns exemplos de código para demonstrar o que o NilObject disse:

- (void)loadView
{
    // create and configure the table view
    myTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStyleGrouped];   
    myTableView.delegate = self;
    myTableView.dataSource = self;
    myTableView.scrollEnabled = NO;
    self.view = myTableView;

    self.view.autoresizesSubviews = YES;
}

- (void)viewDidLoad 
{
  self.title = @"Create group";

  // Right menu bar button is to Save
  UIBarButtonItem *saveButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStyleDone target:self action:@selector(save)];
  self.navigationItem.rightBarButtonItem = saveButtonItem;
  [saveButtonItem release];
}
alamodey
fonte
4
então, entre vocês dois, é preciso dizer que o loadView é onde eu devo fazer a alocação / inicialização do self.view do meu controlador e as visualizações filho devem ser tratadas em viewDidLoad (ou posterior)?
Ryan.scott 22/02/09
2

Para impedir que um loop infinito aconteça quando você lê self.view, chame a super implementação da classe ao carregar uma view. A super implementação alocará um novo UIView para você.

- (void) loadView {
[super loadview];

// init code here...

[self.view addSubView:mySubview1]; //etc..

}
futureelite7
fonte
6
Eu poderia jurar que a documentação da Apple disse que você não deve chamar [super loadView];. Isso foi contradito nos exemplos, mas acho que os documentos disseram corretamente (eu encontrei vários bugs em exemplos ao longo do tempo). [super loadView]é necessário para UITableViewController etc. Contudo! Qualquer configuração pós-carregamento (por exemplo, adicionar sub-visualizações extras) deve ser feita no viewDidLoad.
Ivan Vučica 10/03/11
Eu chamei [super loadView] sem nenhum efeito colateral até agora. Pode ser verdade se você pretende definir a visão pessoal de algo que você mesmo fez.
futureelite7
Se você chamar [super loadView] dentro do loadView, ele tentará carregar a visualização de uma ponta, se disponível com o nome padrão. Então você precisa ter cuidado.
precisa saber é o seguinte
E se você chamar [super-loadView], você inicializa self.view no método loadView Super
Alex Nazarsky
1

A maneira mais fácil de usar o loadView é criar algum tipo de controlador de vista de base, como MyBaseViewController, que é uma subclasse do UIViewController. No método loadView, crie view desta maneira:

-(void) loadView {
    if ([self viewFromNib]) {
        self.view = [self viewFromNib];
    } else {
        self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    }
    self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
    self.view.backgroundColor = [UIColor whiteColor];
}

E quando você precisa criar algum controlador de exibição, basta usar a subclasse de MyBaseViewController e, no controlador loadView, basta chamar [super loadView] como este

//sucblass loadView
-(void) loadView {
    [super loadView];

    //rest of code like this..
    UILabel *myLabel = [[UILabel alloc] initWithFrame:myFrame];
    [self.view addSubview:myLabel];
    [myLabel release];
}
Josip B.
fonte
1

loadView()é chamado quando seu controlador é solicitado a criar o seu self.view. Você pode fazer isso sozinho como

self.view = [UIView alloc] init...];

Ou a classe UIController pai do seu controlador já tem um nome de método -loadView()que inicializa seu self.view na exibição em branco. Então você pode ligar

[super loadView];

Eu realmente recomendo a segunda abordagem, pois incentiva a herança. Somente se o seu controlador de exibição não for herdado diretamente do UIViewController.

Dulguun Otgon
fonte
0

A definição dada pela Apple no viewDidLoad mencionou que é chamada após o carregamento da visualização do controlador na memória. Para colocá-lo em um termo simples, é o primeiro método a carregar.

Você pode estar pensando em que condição esse método será totalmente utilizado? A resposta é, basicamente, o que você deseja que o aplicativo carregue primeiro. Por exemplo, você pode querer uma cor de fundo diferente, em vez de branco, talvez possa escolher o azul.

Gulsan Borbhuiya
fonte