2009-02-18 12 views
9

Considere el siguiente método main() la que se encontraría la mayoría de las aplicaciones de iPhone:¿Por qué la función main() de una aplicación de iPhone nunca tiene la oportunidad de terminar?

int main(int argc, char *argv[]) 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    int retVal = UIApplicationMain(argc, argv, nil, nil); 
    [pool release]; 
    return retVal; 
}

En cada aplicación para el iPhone que me he encontrado en el simulador con éstos (incluyendo varios proyectos de ejemplo proporcionados por Apple), el hilo no sale UIApplicationMain() y cualquier código restante en main() nunca se ejecuta. ¿Es este comportamiento esperado?

He verificado que las declaraciones después de UIApplicationMain() nunca se ejecutan al recorrer el código con un depurador. Cuando el usuario detiene una aplicación (presionando el botón "Inicio", por ejemplo), el seguimiento de la pila resultante muestra que finalmente se llama al [UIApplication _terminateWithStatus:]. Esta función llama al método applicationWillTerminate: del delegado de su aplicación. Una vez que termina, [UIApplication _terminateWithStatus:] parece matar/salir del hilo.

¿Alguien puede confirmar que así es como se espera que main() funcione, o al menos confirme el mismo comportamiento en su máquina?

Respuesta

19

La pregunta inicial fue: "¿Por qué la función main() no es una de aplicación para el iPhone vez tienes la oportunidad de terminar?"

respuesta corta: Debido UIApplicationMain() se codifica tal que nunca vuelve .

Después de hacer varias pruebas en Simulator y en el dispositivo, y pedirle a otro desarrollador que haga las mismas pruebas, he confirmado que UIApplicationMain nunca regresa. Cuando el usuario finaliza una aplicación normalmente presionando el botón Inicio, el programa finaliza finalmente dentro de un método UIAplication no publicado llamado _terminateWithStatus. Este método llama a exit (0).

Este comportamiento coincide con el de la función NSApplicationMain (que es la versión de AppKit/Cocoa de la función UIApplicationMain). La documentación de NSApplicationMain() indica claramente que nunca volverá.

He enviado un error (6600198) a Apple solicitando que se corrija la documentación oficial (y la plantilla de Xcode para main.m) para indicar que UIApplicationMain() nunca regresa. Si bien esto no es un problema funcional, la plantilla y los documentos actuales son engañosos.

Gracias a todos por su aporte y lluvia de ideas!

+2

Actualización: Me complace informar que Apple modificó la documentación oficial de UIApplicationMain() y cerró mi error. La documentación ahora incluye lo siguiente: aunque se especifique un tipo de retorno entero, esta función nunca regresa. Cuando los usuarios finalizan una aplicación de iPhone presionando el botón de Inicio, la aplicación sale inmediatamente llamando a la función del sistema de salida con un argumento de cero. " –

1

Después de [la liberación del grupo] no hay nada para iniciar sesión?

+0

esa teoría debería ser fácil de verificar, simplemente inicie sesión antes del lanzamiento. –

+0

Lo probé usando un depurador antes de publicar para verificar que el hilo nunca sale realmente de la función UIApplicationMain() (es decir, NSLog() nunca se ejecuta). Probablemente debería haber mencionado eso en la pregunta. –

1

tratando utilizando fprintf y ver qué pasa

int main(int argc, char *argv[]) 
{ 
    /* 
     ... 
    same as above 
     ... 
    */ 
    [pool release]; 
    char file_name = "/tmp/log" 

    FILE *file = fopen(file_name, "w"); 

    fprintf(file_name, "END\n"); 
} 

y nos dicen lo que pasa

También pensé en la forma más sencilla de comprobar era establecer un derecho punto de quiebre en el retorno

en gdb do

b main.c:x 

donde x es el número de línea de la declaración s esultados

+0

Lo siento, debería haber mencionado en la pregunta que pasé por main() en un depurador para verificar que el hilo nunca salga de UIApplicationMain(). Realmente parece que cuando detienes una aplicación de iPhone presionando el botón "Inicio", el comportamiento esperado es simplemente matar el hilo antes de que salga main(). –

+0

bien que solo confirma que la teoría de [pool release] que impide el logggin es falsa. – hhafez

3

Probar:

int main(int argc, char *argv[]) 
{ 
    NSLog(@"Step 0"); 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    NSLog(@"Step 1"); 
    int retVal = UIApplicationMain(argc, argv, nil, nil); 
    NSLog(@"Step 2"); 
    [pool release]; 
    NSLog(@"Step 3"); 
    return retVal; 
} 

Puede ser que la liberación de la piscina es la prevención de la tala de árboles en cuyo caso se obtendría el paso 2, pero no el paso 3.

Si el paso 2 ISN' Si se está imprimiendo, es casi seguro que algo está mal con UIApplicationMain; existe la posibilidad de que no vuelva, por lo tanto, coloque las declaraciones NSLog (paso 1.1, paso 1.2, ...) en varios puntos y ejecútelo para encontrar el último mensaje .

Seguir perforando (Paso 1.7.1, 1.7.2, .... 1.7.6.3.2, ...) - con el tiempo, rastreará la línea exacta (independientemente de la profundidad de la jerarquía de llamadas) cuando los mensajes de registro dejan de registrarse y esa línea será su culpable (ya sea "apagar" el registro o salir sin regresar normalmente).

Un fragmento más me encontré en la web:

=====

Cuando se utiliza esta línea:

int retVal = UIApplicationMain(argc, argv, @"MyApp", @"MyApp"); 

La primera MiApl es su principal aplicación clase delegado. El segundo es la clase a la que SpringBoard envía notificaciones táctiles.

Además, si usa el SDK, y tiene una punta principal definida en la información.plist, entonces usted puede dejar la llamada como:

int retVal = UIApplicationMain(argc, argv, nil, nil); 

como todo lo que será cubierto al crear sus xibs.

=====

Ahora no sé lo suficiente sobre el desarrollo del iPhone (xibs específicamente) para saber lo que el último bit incluso medios (o si se ha configurado correctamente) pero suena como otra fase de compilación.

Sin embargo, mi primer pensamiento al leer esto es que Springboard llamará a su clase de delegado cuando se presionen los botones para pedirle que haga algo (como cerrar con gracia). Si no puede preguntarle (es decir, sin delegado), es probable que tenga derecho a cerrarlo como lo considere oportuno, como con [UIApplication _terminateWithStatus:].

En el mundo de Windows, probablemente envíe un mensaje de renuncia a la ventana principal, pero, como ya dije, el desarrollo de iPhone puede ser diferente.

Aún así, es una avenida para investigar. Me interesaría ver qué llamadas se hicieron a un delegado si me proporcionó uno. El código incluido en el fragmento anterior tenía esto:

@implementation MyApp 
- (void) applicationDidFinishLaunching:(id)unused { 
    rect = [ UIHardware fullScreenApplicationContentRect ]; 
    rect.origin.x = 0.0f; 
    rect.origin.y = 0.0f; 
    window = [ [ UIWindow alloc ] initWithContentRect: rect ]; 
    [ window makeKeyAndVisible ]; 
    view = [ [ MyAppView alloc ] initWithFrame: rect ]; 
    [ window setContentView: view ]; 
} 
- (void) dealloc { 
    [ window release ]; 
    [ view release ]; 
    [ super dealloc ]; 
} 

Así que tal vez un delegado con dealloc() es el secreto para conseguir que salga de nuevo a main(). ¿Por qué no le das una oportunidad? Puede acercarlo más a su objetivo, incluso si no resuelve el problema central.

+0

Debería haber mencionado que pasé por main() en un depurador para verificar que el hilo nunca sale de UIApplicationMain(). Dicho esto, también realicé tu prueba por el bien de la claridad; "Paso 2" y "Paso 3" no aparecen en la consola. –

1

Después de llamar a la función UIApplicationMain se inicia su aplicación (estableciendo un runloop, etc.) y todo el trabajo debe realizarse fuera del contexto de main (si necesita ejecutarlo en main, hágalo antes de ese punto). Al salir de una aplicación, generalmente es más eficiente permitir que el sistema operativo limpie la memoria.

+0

De acuerdo. Mi preocupación no es que se haya lanzado el grupo, sin embargo, con la posibilidad de que mi propia aplicación esté haciendo algo mal y no termine correctamente (en base a los documentos de Apple, main() debería terminar). Pero tiene un buen punto con respecto a la eficacia de apagado/limpieza y evitar llamadas dealloc. –

0

Tengo que no volver experiencia también. Y han establecido puntos de ruptura para verificar exactamente como dijo Clint.

wisequark tiene un buen punto.

buen tema. me hace sentir más cómodo que no soy el único que tiene la pregunta.

Cuestiones relacionadas