objective-c exception-handling nserror

objective c - Excepciones de Objective-C



exception-handling nserror (7)

Acabo de completar un curso de programación de aplicaciones para iPhone. Como parte del curso, vi

  • Objective-C proporciona manejo de excepciones utilizando la directiva @try
  • La biblioteca del sistema no usa el manejo de excepciones, prefiriendo return nil

Pregunté si debería usar el manejo de excepciones para el nuevo código que escribí (por ejemplo, si escribo tanto el front-end como el código lógico, para que la comunicación entre ellos esté en mis manos) pero me dijeron que no, uno no debería usar excepciones para nuevos código. (Pero no dio más detalles, luego la clase continuó, pensé que tal vez el motivo se aclararía más tarde ...)

Sin duda, las excepciones son superiores a return nil ? Puede capturar determinados tipos, no tiene la tentación de ignorarlos ignorando el tipo de devolución de una función que normalmente tiene éxito, tiene mensajes de texto que pueden registrarse, permiten que su código se centre en el caso normal y así sea más legible. Por qué usar excepciones

¿Entonces, qué piensas? ¿Fue mi entrenador correcto para no usar las excepciones de Objective-C? Si es así, ¿por qué?


Creo que tu entrenador es correcto. Puede hacer todo tipo de argumentos a favor y en contra de las excepciones, pero la conclusión es que si desea que su código "huela" correctamente a un desarrollador experimentado de Cocoa, implementará su aplicación utilizando los mismos patrones de diseño que Apple usa en su código y en sus marcos. Eso significa NSError y NSError s en lugar de excepciones.

Las ventajas de no usar excepciones son, por lo tanto, principalmente en torno a la coherencia y la familiaridad.

Otra cosa a considerar es que un nil en el Objetivo C suele ser bastante "seguro". Es decir, puede enviar cualquier mensaje a nil y su aplicación no se bloqueará.

(También debo señalar que Apple usa excepciones en algunos lugares, generalmente donde está utilizando una API incorrectamente).


Creo, y otros me corregirán si estoy equivocado, que las Excepciones deberían usarse para detectar errores del programador, mientras que el manejo de errores del tipo NSError debe usarse para condiciones excepcionales que ocurren mientras el programa se está ejecutando.

Y en cuanto a devolver nil , eso no es todo: las funciones que pueden tener problemas no solo devuelven un nil , sino que también pueden (y deberían) proporcionar más información utilizando el objeto NSError que se pasa como parámetro.

Ver también


El tipo de manejo de errores utilizado depende de lo que está tratando de lograr. Casi todos los métodos de Apple NSError un objeto NSError que se puede acceder por error.

Este tipo de manejo de errores se puede usar junto con un bloque try-catch dentro de una sección de código:

-(NSDictionary *)getDictionaryWithID:(NSInteger)dictionaryID error:(NSError **)error { @try { //attempt to retrieve the dictionary } @catch (NSException *e) { //something went wrong //populate the NSError object so it can be accessed } }

En pocas palabras, el propósito del método determina el tipo de manejo de errores que debe usar. Pero, en este ejemplo anterior, puede usar ambos.

Un uso común para el bloque try-catch:

@try { [dictionary setObject:aNullObject forKey:@"Key"]; } @catch (NSException *e) { //one of the objects/keys was NULL //this could indicate that there was a problem with the data source }

Espero que esto ayude.


En el programador Cocoa y iOS, las excepciones se utilizan para indicar un error del programador no recuperable. Cuando los marcos generan una excepción, indica que los marcos han detectado un estado de error que no es recuperable y para el cual el estado interno ahora no está definido.

Además, las excepciones arrojadas a través del código de marco dejan los marcos en un estado indefinido. Es decir, no puedes hacer algo como:

void a() { @throw [MyException exceptionWithName: @"OhNoes!" ....]; } @try { ... call into framework code that calls a() above ... } @catch (MyException e) { ... handle e ... }

Línea de fondo:

Las excepciones no se deben usar en Cocoa para control de flujo, validación de entrada de usuario, detección de validez de datos o para indicar errores recuperables. Para eso, utiliza el patrón NSError** como se documenta aquí (gracias Abizem).

(Tenga en cuenta que hay un pequeño número de API que infringe esto, donde se utiliza una excepción para indicar un estado recuperable. Se han presentado errores contra estos para desaprobar y, finalmente, eliminar estas incoherencias).

Finalmente encontré el documento que estaba buscando:

Importante: debe reservar el uso de excepciones para programación o errores de tiempo de ejecución inesperados, como acceso a colecciones fuera de límites, intentos de mutar objetos inmutables, enviar un mensaje no válido y perder la conexión con el servidor de ventanas. Por lo general, se ocupa de este tipo de errores con excepciones cuando se crea una aplicación en lugar de hacerlo en tiempo de ejecución.

Si tiene un cuerpo de código existente (como una biblioteca de terceros) que usa excepciones para manejar las condiciones de error, puede usar el código tal como está en su aplicación Cocoa. Pero debe asegurarse de que las excepciones de tiempo de ejecución esperadas no escapen de estos subsistemas y terminen en el código de la persona que llama. Por ejemplo, una biblioteca de análisis puede usar excepciones internamente para indicar problemas y permitir una salida rápida de un estado de análisis que podría ser profundamente recursivo; sin embargo, debe tener cuidado de detectar tales excepciones en el nivel superior de la biblioteca y traducirlas a un código o estado de devolución apropiado.


No es seguro lanzar excepciones en circunstancias en las que los recursos no se gestionan automáticamente. Este es el caso del marco de Cocoa (y los marcos vecinos), ya que utilizan el conteo de referencias manual.

Si lanza una excepción, cualquier llamada de release que omita al desenrollar la pila provocará una fuga. Esto debería limitar su escrúpulo solo si está seguro de que no se va a recuperar, ya que todos los recursos se devuelven al sistema operativo cuando finaliza un proceso.

Desafortunadamente, NSRunLoop tiende a detectar todas las excepciones que se propagan a ellos, por lo que si lanzas durante un evento, continuarás al siguiente evento. Esto es, obviamente, muy malo. Por lo tanto, es mejor que simplemente no arrojes.

Este problema se ve disminuido si usa Objective-C recolectado como basura, ya que cualquier recurso representado por un objeto Objective-C se liberará correctamente. Sin embargo, los recursos C (como los descriptores de archivos o la memoria asignada malloc ) que no están incluidos en un objeto Objective-C seguirán teniendo fugas.

Entonces, en general, no arroje.

El Cocoa API tiene varias soluciones para esto, como usted mencionó. La devolución de nil y el patrón NSError** son dos de ellos.

Aclaraciones para ARC

Los usuarios de ARC pueden optar por habilitar o deshabilitar la seguridad de excepción completa. Cuando la seguridad de excepción está habilitada, ARC generará código para liberar referencias fuertes cuando se elimine su alcance, lo que hace que sea seguro usar una excepción en el código . ARC no aplica parches a las bibliotecas externas para permitir el soporte de excepciones en ellas, por lo que debe tener cuidado de dónde arrojar (y especialmente de dónde atrapa), incluso con el soporte de excepción habilitado en su programa.

El soporte de excepción ARC se puede habilitar con -fobjc-arc-exceptions o deshabilitarse con -fno-objc-arc-exceptions . Por defecto, está deshabilitado en Objective-C pero habilitado en Objective-C ++.

La seguridad de excepción completa en Objective-C está deshabilitada de forma predeterminada porque los autores de Clang suponen que los programas de Objective-C no se recuperarán de una excepción de todos modos, y porque hay un gran costo de tamaño de código y una pequeña penalización de rendimiento asociada a esa limpieza. En Objective-C ++, por otro lado, C ++ ya introduce una gran cantidad de código de limpieza, y es mucho más probable que las personas realmente necesiten excepción-seguridad.

Todo esto proviene de la especificación ARC en el sitio web de LLVM .


Personalmente, no veo ninguna razón para no usar excepciones en tu propio código . El patrón de excepción es más limpio para el manejo de errores que

  • siempre teniendo un valor de retorno,
  • asegurándose de que uno de los posibles valores de retorno realmente signifique "error"
  • pasando un parámetro extra que es una referencia a un NSError*
  • rocía tu código con el código de limpieza para cada devolución de error o tienes gotos explícitos para pasar a una sección de limpieza de errores común.

Sin embargo, debe tener en cuenta que no se garantiza que el código de otras personas maneje la excepción correctamente (si es C puro, de hecho no puede manejar las excepciones correctamente). Por lo tanto, nunca debe permitir que una excepción se propague más allá de los límites de su código. Por ejemplo, si lanza una excepción en las profundidades de un método de delegado, debe manejar esa excepción antes de regresar al remitente del mensaje de delegado .


si prefiere excepciones, puede usarlas. si lo hace, le recomiendo que los use con moderación porque se vuelve muy difícil de mantener (puntos de salida adicionales que normalmente tendrá que hacer ejercicio en tiempo de ejecución para comprobar la corrección del programa).

no hay una especificación para las expectativas de manejo de excepciones para los clientes; tienen que mantener su programa basado en los documentos (tedioso, propenso a errores, probablemente no se mantendrá hasta que se produzca una excepción).

si tuviera que usarlos, los usaría solo en casos muy raros y usaría códigos de error o devolvería nulos cuando fuera posible. Además, los usaría internamente en una biblioteca y no expondría a los clientes a excepciones en la interfaz (o los efectos secundarios). No los uso en objc o c ++ (bueno, los atraparé pero no los arrojaré).

como normalmente esperarías, debes evitar usarlos para controlar el flujo del programa (un mal uso común).

es mejor usarlos cuando tienes que escapar de un accidente. si avanza y escribe el código ahora, le recomiendo que solo escriba la interfaz para manejar los errores como parte del flujo del programa y evite escribir excepciones cuando sea posible.

corrección a la publicación original: las variedades de cacao prefieren devolver nada, en algunos casos arrojarán excepciones para ti (atrapar).