iPhone SDK: ¿cuál es la diferencia entre loadView y viewDidLoad?

136

Al trabajar con vistas y controladores de vista en una aplicación de iPhone, ¿alguien puede explicar la diferencia entre loadView y viewDidLoad?

Mi contexto personal es que construyo todas mis vistas desde el código, no uso y no usaré Interface Builder, si eso marca la diferencia.

He descubierto que a menudo cuando agrego código de inicio a loadView, termino con un seguimiento de pila infinito, por lo que normalmente hago todo mi edificio de vista de niño en viewDidLoad ... pero realmente no me queda claro cuándo se ejecuta cada uno, y cuál es el lugar más apropiado para poner el código de inicio. Lo que sería perfecto es un diagrama simple de las llamadas de inicialización.

¡Gracias!

ryan.scott
fuente

Respuestas:

200

Puedo adivinar cuál podría ser el problema aquí, porque lo he hecho:

He descubierto que a menudo cuando agrego código de inicio a loadView, termino con un seguimiento de pila infinito

No lea self.view en -loadView. Solo configúralo , no lo entiendas .

El descriptor de acceso de propiedad self.view llama -loadView si la vista no está cargada actualmente. Ahí está tu recursión infinita.

La forma habitual de construir la vista mediante programación en -loadView, como se demuestra en los ejemplos previos de Interface-Builder de Apple, es más o menos así:

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

Y no te culpo por no usar IB. Me he quedado con este método para todo Instapaper y me encuentro mucho más cómodo con él que con las complejidades de IB, las peculiaridades de la interfaz y el comportamiento inesperado detrás de escena.

Marco
fuente
ahhhh, gracias por una explicación, finalmente! Me alejé del idioma de asignar una variable temporal, luego establecerme en self.view, luego liberar ... parecía algo incómodo, innecesario. Ahora puedo entender por qué esa decisión me habría llevado por el camino donde ahora me encuentro.
ryan.scott
Tengo ese código y no hay recursividad. ¿por qué? -(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

loadViewes el método UIViewControllerque realmente cargará la vista y la asignará a la viewpropiedad. Esta es también la ubicación que una subclase de UIViewControlleranularía si quisiera configurar programáticamente la viewpropiedad.

viewDidLoades el método que se llama una vez que se ha cargado la vista. Esto se llama después de que se llama loadView. Es un lugar donde puede anular e insertar código que realiza una configuración inicial adicional de la vista una vez que se ha cargado.

NilObject
fuente
14
viewDidLoad()

debe usarse cuando carga su vista desde una NIB y desea realizar cualquier personalización después del lanzamiento

LoadView()

se utilizará cuando desee crear su vista mediante programación (sin el uso de Interface Builder)

ashokdy
fuente
Esto puede tener algún problema, tengo una prueba cuando mi controlador de vista no estaba asociado con el archivo NIB, viewDidLoad todavía se llamaba
ruandao
11

Simplemente agregue algunos ejemplos de código para demostrar lo que dijo NilObject:

- (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
fuente
44
entonces, entre ustedes dos, ¿es correcto decir que loadView es donde debería hacer el alloc / init de la vista propia de mi controlador, y las vistas secundarias deberían manejarse en viewDidLoad (o posterior)?
ryan.scott
2

Para evitar que suceda un bucle infinito cuando lee self.view, llame a la súper implementación de la clase cuando carga una vista. La súper implementación asignará una nueva UIView para usted.

- (void) loadView {
[super loadview];

// init code here...

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

}
futureelite7
fuente
66
Podría jurar que la documentación de Apple dice que no debes llamar [super loadView];. Eso se contradijo en los ejemplos, pero creo que los documentos lo dijeron correctamente (con el tiempo he encontrado numerosos errores en los ejemplos). [super loadView]Sin embargo, es necesario para UITableViewController, etc. ¡Sin embargo! Cualquier configuración posterior a la carga (por ejemplo, agregar subvistas adicionales) debe hacerse en viewDidLoad.
Ivan Vučica
He llamado [super loadView] sin ningún efecto secundario hasta ahora. Sin embargo, puede ser cierto si tiene la intención de establecer una visión propia de algo que usted mismo hizo.
futureelite7
Si llama a [super loadView] dentro de loadView, intentará cargar la vista desde una punta si está disponible con el nombre predeterminado. Entonces debes tener cuidado.
Ian1971
Y si llama a [super loadView], inicializa self.view en el método super loadView
Alex Nazarsky
1

La forma más fácil de usar loadView es crear algún tipo de controlador de vista base, como MyBaseViewController, que es una subclase de UIViewController. En su método loadView, crea una vista de esta manera:

-(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];
}

Y cuando necesita hacer un controlador de vista, simplemente usa la subclase de MyBaseViewController y en su controlador loadView simplemente llama [super loadView] de esta manera

//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.
fuente
1

loadView()se llama cuando se le pide a su controlador que cree su self.view. Puedes hacerlo solo como

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

O la clase UIController principal de su controlador ya tiene un nombre de método -loadView()que inicializa su self.view en una vista en blanco. Entonces puedes llamar

[super loadView];

Realmente recomiendo el segundo enfoque, ya que fomenta la herencia. Solo si su controlador de vista no se hereda directamente de UIViewController.

Dulguun Otgon
fuente
0

La definición dada por Apple en viewDidLoad menciona que se llama después de que la vista del controlador se carga en la memoria. Para ponerlo en un término simple, es el primer método que se cargará.

Quizás esté pensando en qué condiciones se utilizará este método por completo. La respuesta es, básicamente, lo que quiera que la aplicación cargue primero. Por ejemplo, es posible que desee un color de fondo diferente, en lugar de blanco, quizás podría elegir azul.

Gulsan Borbhuiya
fuente