2010-11-30 14 views
8

Uno de mis amigos me pidió que no use NSException en aplicaciones de iPhone. La razón por la que dio fue "cuello de botella de rendimiento". Pero no estoy convencido de eso.Uso de NSException en aplicaciones de iPhone

¿Alguien me puede confirmar que debemos restringir el uso de la aplicación NSException en iPhone? Si tiene las mejores prácticas para usar NSException, proporcione eso también.

ACTUALIZACIÓN:

Este link pide que usemos El manejo de excepciones en el nivel de aplicación. ¿Alguien lo ha hecho alguna vez? Por favor, dale las ventajas y cualquier otro impacto que pueda crear.

Respuesta

30

En resumen:

No utilice excepciones para indicar cualquier cosa menos errores irrecuperables

Sólo es apropiado usar @ try/@ captura para hacer frente a errores irrecuperables. Nunca es apropiado usar @ throw/@ try/@ catch para realizar operaciones de flujo de control en iOS o Mac OS X. Incluso entonces, considere cuidadosamente si es mejor usar una excepción para indicar un error irrecuperable o simplemente un bloqueo (call abort()); un accidente a menudo deja significativamente más evidencia.

Por ejemplo, no sería apropiado utilizarlo para atrapar excepciones fuera de límites a menos que su objetivo sea atraparlas y de alguna manera informar el error; luego, normalmente, bloquear o, como mínimo, advertir al usuario que su aplicación está en un estado incoherente y puede perder datos.

El comportamiento de cualquier excepción arrojada a través del código del sistema no está definido.


Puede explicar el "Comportamiento de cualquier excepción lanzada a través del sistema código de la arquitectura no está definido." en detalle?

Sure.

Las estructuras del sistema utilizan un diseño en el que cualquier excepción se considera un error fatal, irrecuperable; un error del programador, para todos los efectos. Hay un número muy limitado de excepciones (heh) a esta regla.

Por lo tanto, en su implementación, los marcos del sistema no se asegurarán de que todo esté necesariamente limpiado adecuadamente si se lanza una excepción que pase por el código de la infraestructura del sistema. Sine la excepción es, por definición, irrecuperable, ¿por qué pagar el costo de la limpieza?

considerar esta pila de llamadas:

your-code-1() 
    system-code() 
     your-code-2() 

es decir, código donde su código llama al código del sistema que llama a más de su código (un patrón muy común, aunque las pilas de llamadas son significativamente más profundas).

Si your-code-2 arroja una excepción, que las excepciones superan system-code significa que el comportamiento no está definido; system-code puede o no dejar su aplicación en un estado indefinido, potencialmente coloso o con pérdida de datos.

O, más enérgicamente: No puede lanzar una excepción en your-code-2 con la expectativa de que pueda atraparla y manejarla en your-code-1.

+0

¿Puede explicar que el "Comportamiento de cualquier excepción arrojada a través del código del sistema no está definido". ¿en detalle? – Krishnan

+0

Se actualizó la pregunta .... – Krishnan

+0

+1, es agradable. ¿Puede decirme por favor que mi suposición con respecto a la excepción no es correcta? Si utilizo NSException en caso de Excepción particular (suponga que Matriz está fuera de límite) .luego se carga todas las clases para verificar la excepción. Responda. – Ishu

0

En general, pregúntese si está tratando de señalar un error, o realmente tiene una condición excepcional? Si lo primero, entonces es una muy mala idea, independientemente de cualquier problema de rendimiento, real o percibido. Si esto último, definitivamente es lo correcto.

+2

No realmente; Las excepciones en iOS son por errores irrecuperables. – bbum

+1

Para mí, las situaciones recuperables son errores :) – jer

6

He utilizado el manejo de excepciones para mi bastante intensivo audio app sin ningún tipo de problema. Después de mucha lectura y un poco de análisis de evaluación comparativa y desensamblaje, llegué a la controvertida conclusión de que no hay una razón real para no usarlos (inteligentemente) y muchas razones para no hacerlo (punteros punteros NSError, interminables condicionales ... ¡puaj!). La mayoría de lo que dice la gente en los foros es simplemente repetir los Apple Docs.

de entrar en un poco de detalle en this blog post pero voy a esbozar mis resultados aquí:

Mito 1: @ try/@ captura/@ finalmente es demasiado costoso (en términos de CPU)

En mi iPhone 4, lanzar y atrapar 1 millón de excepciones toma aproximadamente 8.5 segundos. Esto equivale a solo 8,5 microsegundos para cada uno. ¿Caro en su hilo de CoreAudio en tiempo real? Tal vez un poco (pero nunca arrojarías excepciones, ¿verdad?), Pero un retraso de 8,5 μs en el UIAlert diciéndole al usuario que hubo un problema al abrir su archivo, ¿se va a notar?

Mito 2: Bloques @try tienen un costo de 32 bits En iOS

Los documentos de Apple hablan de "bloques @try de costo cero en 64 bits" y afirman que 32 bits incurre en un costo. Un pequeño análisis de benchmarking y desensamblaje parece indicar que hay bloques @try de costo cero en iOS de 32 bits (procesador ARM) también. ¿Apple quiere decir 32bit Intel?

Mito 3: importa que las excepciones lanzado a través de cacao Los marcos son Indefinido

sí, son "indefinido", pero ¿qué haces tirar a través del marco de Apple de todos modos? Por supuesto Apple no los maneja por usted. El objetivo de implementar el manejo de excepciones para errores recuperables es manejarlos localmente, pero no cada línea individual "localmente".

Un caso de borde aquí es con métodos como NSObject:performSelectorOnMainThread:waitUntilDone:. Si el último parámetro es SÍ, esto actúa como una función síncrona, en cuyo caso se le puede perdonar que espere que la excepción suba al alcance de su llamada. Por ejemplo:

///////////////////////////////////////////////////////////////////////// 
#pragma mark - l5CCThread 
///////////////////////////////////////////////////////////////////////// 

@interface l5CCThread : NSThread @end 

@implementation l5CCThread 

- (void)main 
{ 
    @try { 

     [self performSelectorOnMainThread:@selector(_throwsAnException) withObject:nil waitUntilDone:YES]; 

    } @catch (NSException *e) { 
     NSLog(@"Exception caught!"); 
    } 
} 
- (void)_throwsAnException { @throw [NSException exceptionWithName:@"Exception" reason:@"" userInfo:nil]; } 

@end 

///////////////////////////////////////////////////////////////////////// 
#pragma mark - l5CCAppDelegate 
///////////////////////////////////////////////////////////////////////// 

@implementation l5CCAppDelegate 

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    l5CCThread *thd = [[l5CCThread alloc] init]; 
    [thd start]; 

    return YES; 
} 
// ... 

En este caso la excepción pasaría "a través del marco de cacao" (bucle de ejecución del hilo principal) falta de su captura y estrellarse. Puede solucionar este problema fácilmente usando el GCD dispatch_synch y poniendo en su argumento de bloque la llamada al método más cualquier manejo de excepción.

¿Por qué utilizar NSException de más de

Cualquiera de NSError que alguna vez ha hecho trabajo en uno de los marcos más antiguas basadas-C como Core Audio sabe lo que es una tarea que está comprobando, la manipulación y notificación de errores. El beneficio principal @ try/@ catch y NSExceptions es hacer que su código sea más limpio y fácil de mantener.

Supongamos que tiene 5 líneas de código que funcionan en un archivo. Cada uno podría arrojar uno de, por ejemplo, 3 errores diferentes (por ejemplo, espacio en disco, error de lectura, etc.). En lugar de envolver cada línea en un condicional que busca un valor de retorno NO y luego subcontrata la investigación del puntero NSError a otro método ObjC (o peor, utiliza una macro #define), ajusta las 5 líneas en una sola @try y manejar cada error allí mismo. ¡Piensa en las líneas que ahorrarás!

Al crear subclases de NSException, también puede centralizar fácilmente los mensajes de error y evitar tener su código lleno de ellos. También puede distinguir fácilmente las excepciones "no fatales" de su aplicación de los errores fatales del programador (como NSAssert). También puede evitar la necesidad de la constante "nombre" (el nombre de la subclase, es el "nombre").

ejemplos de todo esto y más detalles acerca de los puntos de referencia y desmontaje son on this blog post ...

excepciones más try/catch/finally es el paradigma utilizado por casi todos los otros idiomas principales (C++, Java, PHP, Ruby, Python). Tal vez es hora de abandonar la paranoia y abrazarla también ... al menos en iOS.

+6

Sugerir que está bien usar NSExceptions para errores recuperables y control de flujo es incorrecto. Los marcos explícitamente no son compatibles. – bbum

+0

Además del punto (más importante) que hace el bbum, me es difícil ver cómo Try/catch mejoró la ligibilidad: si todo lo que quieres es no recuperar, regresa temprano y con frecuencia. Si tienes una cascada de capturas, ¿cómo es eso mejor? – danyowdee

+2

Porque centraliza el manejo de cada tipo de error en un solo lugar para un bloque de código dado en lugar de por línea. –

Cuestiones relacionadas