2009-04-02 15 views
10

Soy desarrollador de Microsoft desde hace mucho tiempo y soy nuevo en el desarrollo de iPhone con XCode. Entonces, estoy leyendo un libro y repasando ejemplos tratando de enseñarme cómo escribir una aplicación de iPhone usando Objective-C. Todo ha sido bueno hasta ahora, sin embargo, de vez en cuando me encuentro con el mensaje genérico 'objc_exception_throw' en tiempo de ejecución. Cuando esto sucede, la fuente de esta excepción es muy difícil de encontrar. Después de un poco de prueba y error encontré mi respuesta. Uno de los parámetros fue mal escrito.Excepción de depuración lanzada en Objective C y XCode

Como puede ver a continuación, escribí mal el parámetro 'otherButtonTitles' dejando fuera el segundo botón 't'.

UIAlertView *alert = [[UIAlertView alloc] 
         initWithTitle:@"Date and Time Selected" 
         message:message 
         delegate:nil 
         cancelButtonTitle:@"Cancel" 
         otherButonTitles:nil]; 

La razón por la que esto me llevó tiempo es porque el código se creó correctamente. ¿Es este comportamiento normal para el compilador Objective-C? Estoy acostumbrado a que la compilación falle en el compilador .NET cuando hago un error de sintaxis común como este. ¿Hay alguna configuración de compilación que pueda cambiar para que el built-break falle cuando cometo estos errores?

+1

Alguien con más reputación de la que debería editar el título de esto a algo así como "Depurar y prevenir 'objc_exception_throw'". –

Respuesta

25

Primero y ante todo, abierta ~/.gdbinit (que es el archivo llamado .gdbinit en su directorio personal - sí, comienza con un punto) y poner esto en él:

fb -[NSException raise] 
fb objc_exception_throw 
fb malloc_error_break 

Eso va a inicializar el BGF con tres puntos de ruptura predeterminados Cuando ocurran, GDB detendrá su aplicación y le mostrará el seguimiento de la pila. Esto está muy bien integrado con Xcode, por lo que podrá recorrer su código haciendo clic en los elementos traza de la pila tan pronto como se produzca una excepción en alguna parte o falle un malloc.

A continuación, abra el panel de Get Info en su proyecto (o seleccione su proyecto (arriba elemento de la Groups & Files) y pulsa cmd-i), vaya a la pestaña Build y ajuste de Base SDKDevice - iPhone OS [someversion] a su proyecto. Desplácese hasta la parte inferior y busque la sección GCC 4.0 - Warnings. Ahí; encienda tantas advertencias como se sienta cómodo, pero asegúrese de activar Treat Warnings as Errors (este es el equivalente a GCC_TREAT_WARNINGS_AS_ERRORS). En lo personal, lo tengo configurado para esto:

GCC Warning Build Settings http://lhunath.lyndir.com/stuff/gcc_warnings.png

Ahora debería estar recibiendo advertencias del compilador para la mayoría de las cosas que pueden hacer el mal en el código y el compilador no permite ejecutar el código hasta que a solucionarlos. Cuando las cosas pasan la nariz del compilador, debería ser capaz de encontrar el problema fácilmente con GDB rompiendo en un lugar conveniente.

También debe consultar NSZombie*. Estas son variables de entorno que son muy útiles para romper con malas asignaciones de memoria o situaciones de acceso. Por ejemplo; wih NSZombieEnabled nada será realmente lanzado; en dealloc se sobrescribirá con _NSZombie y si intenta acceder nuevamente a esta memoria desasignada (desreferenciando un puntero desastrado) obtendrá algo para romperse en GDB, en lugar de que la llamada se realice de forma normal, solo se emitirá al azar datos (que, por supuesto, no es lo que querías). Para obtener más información al respecto, consulte http://www.cocoadev.com/index.pl?NSZombieEnabled.

+0

NOTA: Para que la sección "Advertencias de GCC 4.0" aparezca en su configuración (como se muestra arriba), debe tener el SDK base y el SDK activo configurado en el Dispositivo y no en el Simulador. – rtemp

+0

Además, cuando habilita "Tratar advertencias como errores", seguirá viendo las advertencias como antes, pero obtendrá 1 error un tanto engañoso "Falló el comando/Desarrollador/Plataformas/iPhoneOS.platform/Developer/usr/bin/gcc-4.0 código de salida 1 ". Este error desaparecerá cuando se eliminen todas las advertencias. – rtemp

8

Los parámetros mal escritos generalmente deberían dar como resultado un "Advertencia: tal y tal objeto no responde al selector x" en amarillo en la línea en cuestión. Creo que esto está activado por defecto, ya que no tuve que cambiar ninguna configuración del compilador para ver esto.

También, cuando me encuentro con una excepción no capturada, a veces es beneficioso para caer en la consola GDB (debería aparecer cuando se ejecuta la aplicación) y escriba lo siguiente para obtener trazas de todas las discusiones:

taa bt

+0

"taa bt" es una abreviatura para "aplicar todas las trazas inversas" y simplemente imprime una traza inversa para todos los hilos –

1

La razón por la cual no es un error de compilación, se debe a que es perfectamente válido enviar un mensaje desconocido en tiempo de compilación a cualquier objeto (y cualquier objeto puede configurarse para manejar mensajes dinámicamente también). Todas las llamadas a métodos son realmente mensajes que se envían a objetos.

En general, si ve alguna advertencia, debería abordarlas, ya que en la mayoría de los casos pueden provocar problemas (como ha visto). El aspecto engañoso es que si compila un archivo una vez y solo tiene advertencias, si compila otras clases sin realizar cambios en la clase que tiene advertencias, la advertencia no se mostrará en los mensajes del compilador. Así que de vez en cuando es posible que desee "limpiar todos los objetivos" y construir de nuevo para asegurarse de que no se perdió ninguna advertencia.

2

Lo que hizo no es un error en tiempo de compilación, porque el tiempo de ejecución de Objective-C verifica en tiempo de ejecución si un objeto puede responder al mensaje que le envía.

Recomiendo añadir esta opción a su objetivo o proyecto de construcción:

GCC_TREAT_WARNINGS_AS_ERRORS = YES 
9

usar siempre el ajuste -Werror GCC (GCC_TREAT_WARNINGS_AS_ERRORS = YES). Nunca debe tener advertencias en su código y este es un ejemplo donde la advertencia es un error crítico.

Además, si obtiene un objc_exception_throw, cambie a la consola (Command-shift-R) y busque la primera dirección de número "bajo".

2009-04-01 13:25:43.385 CrashExample[41720:20b] Stack: (
    2528013804, 
    2478503148, 
    2528036920, 
    2528053460, 
    2358032430, 
    11076, 
    11880, 
    816174880, 
    345098340, 
    145973440, 
    816174880, 
) 

En este caso sería "11076". Escriba en la consola:

info line *11076 

Esto le dirá la línea en su código donde se produjo la excepción.

+0

Ese es un gran consejo. Otra cosa que añadir es establecer un punto de interrupción global en "objc_exception_throw", que se romperá automáticamente cuando su código hace algo que arroja una excepción. –

Cuestiones relacionadas