Objetivo-C: afirmación frente a excepción frente a error

79

En Cocoa, ¿cuándo debería usar NSAssert, NSException, NSError?

Esto es lo que he estado pensando:

NSAssert - ¿Al crear cualquier programa cliente utilizado para el beneficio de los programadores para verificar las reglas, convenciones, suposiciones o condiciones previas y posteriores?

NSException : al crear una biblioteca de terceros para el beneficio de otros programadores que usan la biblioteca, para que sepan de inmediato cuando una entrada no es válida.

NSError : ¿al interactuar con un sistema externo para obtener datos como un archivo, una base de datos o un servicio web que no garantiza que me dé un resultado?

Tobias
fuente

Respuestas:

103

Un NSAssert generará una excepción cuando falle. Por lo tanto, NSAssert está ahí para ser una forma corta y fácil de escribir y verificar cualquier suposición que haya hecho en su código. No es (en mi opinión) una alternativa a las excepciones, solo un atajo. Si una afirmación falla, algo ha ido terriblemente mal en su código y el programa no debería continuar.

Una cosa a tener en cuenta es que NSAssert no se compilará en su código en una versión de lanzamiento, por lo que generalmente se usa para verificar la cordura durante el desarrollo. De hecho, tiendo a usar una macro de aserción personalizada que siempre está activa.

Las veces en que usaría @throwsu propia NSException es cuando definitivamente la desea en una versión de lanzamiento, y en cosas como bibliotecas públicas / interfaz cuando algunos argumentos no son válidos o se le ha llamado incorrectamente. Tenga en cuenta que no es una práctica estándar hacer @catchuna excepción y continuar ejecutando su aplicación. Si intenta esto con algunas de las bibliotecas estándar de Apple (por ejemplo, Core Data), pueden suceder cosas malas. De manera similar a una afirmación, si se lanza una excepción, la aplicación generalmente debería terminar con bastante rapidez porque significa que hay un error de programación en alguna parte.

NSErrors debe usarse en sus bibliotecas / interfaces para errores que no son errores de programación y de los que se pueden recuperar. Puede proporcionar información / códigos de error a la persona que llama y ellos pueden manejar el error limpiamente, alertar al usuario si corresponde y continuar con la ejecución. Por lo general, esto sería para cosas como un error de archivo no encontrado o algún otro error no fatal.

Mike Weller
fuente
15
Para decirlo con más fuerza, una NSException no debe usarse para indicar un error recuperable.
bbum
28
En otras palabras: NSException == clase de error de Java de Obj-C y NSError == clase de excepción de Java de Obj-C. ¡Hurra por la coherencia en los términos!
Tustin2121
2
En realidad, NSAssert se compilará en su código si no agrega NS_BLOCK_ASSERTIONS en sus archivos de prefijo precompilados. Lea la respuesta a continuación (solo obtenga 50 para elogiar ahora :)
likid1412
3

La convención en Cocoa es que una excepción indica un error del programador. Una gran cantidad de código, incluido el código marco, no está diseñado para funcionar correctamente después de que se lanza una excepción.

Cualquier tipo de error que deba recuperarse se representa con un NSError. También hay un sistema para presentar NSErrorcorreos electrónicos al usuario. Como usted dice, esto es principalmente útil para recursos externos falibles.

Conceptualmente, una aserción es una declaración de que un predicado dado siempre se evalúa como verdadero; si no es así, el programa no funciona. Si bien su comportamiento se puede modificar, la NSAssertfamilia es por defecto una forma conveniente de lanzar NSInternalInconsistencyExceptions (con la opción de desactivarlos en las versiones de lanzamiento).

Jens Ayton
fuente
2

Editar: en Xcode 4.2, las afirmaciones están desactivadas de forma predeterminada para las versiones de lanzamiento,

Ahora NSAssert no se compilará en su código en una compilación de lanzamiento , pero puede cambiarlo en la configuración de compilación


@ Mike Weller, hay un error en tu respuesta.

Una cosa a tener en cuenta es que NSAssert no se compilará en su código en una versión de lanzamiento , por lo que generalmente se usa para verificar la cordura durante el desarrollo.

En realidad, NSAssert se compilará en su código si no agrega NS_BLOCK_ASSERTIONSsus archivos de prefijo precompilados.

En Nota Técnica TN2190 podemos encontrar:

Es importante especificar macros como NDEBUG para desactivar C assert o NS_BLOCK_ASSERTIONS para desactivar Foundation's NSAssert para sus archivos de prefijo precompilados

O puede leer este: ¿Cómo saber si NSAssert está deshabilitado en las versiones de versiones?

likid1412
fuente
1

En general, las excepciones se utilizan para señalar errores del programador; son cosas que no deberían suceder. Los errores se utilizan para señalar condiciones de error que pueden surgir en el funcionamiento normal del programa: errores de usuario, básicamente, o condiciones externas que deben ser verdaderas pero que pueden no serlo. Por lo tanto, intentar eliminar algún elemento bloqueado en un documento podría ser un error, e intentar descargar un archivo sin una conexión a Internet sería un error, pero intentar acceder a un elemento no válido de una colección sería una excepción.

Las afirmaciones se utilizan normalmente en las pruebas, y AFAIK no se utiliza como un mecanismo general de manejo de errores como los demás.

Arrojar
fuente
Las afirmaciones se pueden utilizar para hacer cumplir invariantes. Por ejemplo, NSParameterAssert(someParam != nil);aplicará el invariante de que el parámetro especificado no debe ser nulo.
Lily Ballard
@Kevin Ballard: Las afirmaciones normalmente se definen a partir de versiones de lanzamiento, o al menos fueron la última vez que verifiqué, así que, como dije, no son un mecanismo general de manejo de errores.
Chuck
1
Pueden serlo, pero no se omiten de forma predeterminada. Tienes que cambiar una configuración de compilación para obtener ese comportamiento.
Lily Ballard