unreachable - try catch swift 4 example
Manejo rápido de errores para métodos que no se lanzan (6)
Ante una excepción lanzada desde un método que no puede lanzar. Descubrí que esta excepción fue lanzada desde la parte object-c de la API. Así que deberías atraparlo al estilo antiguo usando object-c.
En primer lugar, cree la clase object-c que toma varios bloques en el método init, para probar, capturar y finalmente.
#import <Foundation/Foundation.h>
/**
Simple class for catching Objective-c-style exceptions
*/
@interface ObjcTry : NSObject
/**
* Initializeer
*
* @param tryBlock
* @param catchBlock
* @param finallyBlock
*
* @return object
*/
- (_Nonnull id)initWithTry:(nonnull void(^)(void))tryBlock catch:(nonnull void(^)( NSException * _Nonnull exception))catchBlock finally:(nullable void(^)(void))finallyBlock;
@end
En el archivo .m:
#import "ObjcTry.h"
@implementation ObjcTry
- (_Nonnull id)initWithTry:(nonnull void(^)(void))tryBlock catch:(nonnull void(^)( NSException * _Nonnull exception))catchBlock finally:(nullable void(^)(void))finallyBlock
{
self = [super init];
if (self) {
@try {
tryBlock ? tryBlock() : nil;
}
@catch (NSException *exception) {
catchBlock ? catchBlock(exception) : nil;
}
@finally {
finallyBlock ? finallyBlock() : nil;
}
}
return self;
}
@end
En segundo lugar, agregue sus encabezados al archivo Encabezado puenteado.
#import "ObjcTry.h"
Y úsalo en tu código swift así:
var list: [MyModel]!
_ = ObjcTry(withTry: {
// this method throws but not marked so, you cannot even catch this kind of exception using swift method.
if let items = NSKeyedUnarchiver.unarchiveObject(with: data) as? [MyModel] {
list = items
}
}, catch: { (exception: NSException) in
print("Could not deserialize models.")
}, finally: nil)
Esta pregunta ya tiene una respuesta aquí:
¿Cómo manejar los errores de los métodos o códigos que no se lanzan explícitamente?
Envolviéndolo, un bloque do / catch da como resultado una advertencia del compilador:
"''catch'' block is unreachable because no errors are thrown in ''do'' block"
Viniendo de los antecedentes de C # / JAVA, es una rareza por decir lo menos. Como desarrollador, debería poder proteger y envolver cualquier bloque de código en el bloque do / catch. El hecho de que un método no esté marcado explícitamente con "tirar" no significa que no se produzcan errores.
Como han mencionado otros, no debe detectar estos errores, debe corregirlos , pero en caso de que desee ejecutar más código antes de que finalice el programa, use NSSetUncaughtExceptionHandler
en AppDelegate
en la función applicationdidFinishLaunchingWithOptions
.
La descripción de la función:
Cambia el controlador de errores de nivel superior.
Establece la función de manejo de errores de nivel superior donde puede realizar el registro de último minuto antes de que finalice el programa.
Hay una diferencia entre ERRORES y EXCEPCIONES. Swift solo se ocupa de los errores que se EXPLICAN explícitamente y no tiene capacidad nativa para tratar con EXCEPCIONES. Como han comentado otros, los ERRORES se deben lanzar y no se puede detectar lo que no se arroja.
Por el contrario, Objective-C @ try- @ catch se ocupa de excepciones , no de errores,. Algunos métodos objc pueden causar excepciones pero no declararlos de ninguna manera al compilador. por ejemplo, FileHandle.write. Estas excepciones están más estrechamente alineadas con la RuntimeException de Java, que tampoco es necesario declarar.
Hay algunas situaciones, como el manejo de archivos, en las que sería bueno manejar las excepciones de forma limpia en Swift y es posible mediante el uso de un contenedor de Objective-C. Consulte http://.com/questions/34956002/how-to-properly-handle-nsfilehandle-exceptions-in-swift-2-0
Código reproducido aquí:
#ifndef ExceptionCatcher_h
#define ExceptionCatcher_h
#import <Foundation/Foundation.h>
NS_INLINE NSException * _Nullable tryBlock(void(^_Nonnull tryBlock)(void)) {
@try {
tryBlock();
}
@catch (NSException *exception) {
return exception;
}
return nil;
}
#endif /* ExceptionCatcher_h */
Entonces llamándolo desde Swift:
let exception = tryBlock {
// execute dangerous code, e.g. write to a file handle
filehandle.write(data)
}
if exception != nil {
// deal with exception which is of type NSException
}
Lo que está pidiendo no es posible en Swift, ya que Swift no tiene capacidad para manejar los errores de tiempo de ejecución, como fuera de los límites, violaciones de acceso o desempaquetado forzado fallido durante el tiempo de ejecución. Su aplicación terminará si se produce alguno de estos graves errores de programación.
Algunos punteros:
- P: ¿Cómo manejar EXC_BAD_ACCESS? A: no es posible
- P: ¿Cómo manejar el error forzado desenvolver? A: no es posible
- P: ¿Cómo manejar el array fuera de límites? A: no es posible
Larga historia corta: No ataje el manejo de errores en Swift. Juega seguro, siempre.
Solución alternativa: si es absolutamente necesario detectar errores de tiempo de ejecución, debe utilizar los límites del proceso para proteger. Ejecute otro programa / proceso y comuníquese utilizando tuberías, enchufes, etc.
Simplemente no puedes. La declaración completa do-try-catch
o do-catch
está destinada a ser utilizada para detectar errores no manejados y ...
Quiero decir que no tiene sentido capturar el error si no se produce ningún error en primer lugar ... No veo ningún escenario por el que querría hacer tal cosa, solo hace que el compilador se enoje sin ninguna razón.
Es el mismo escenario si se desenvuelve de manera segura opcional con las declaraciones if let
o guard let
.
guard let smth = smthOpt?.moreSpecific else { return }
//Compiler gives warning - unused variable smth. You wouldn''t declare the variable and then not use it, or you would?
Simply Do-Catch no debe utilizarse para un uso seguro y no veo ninguna razón por la cual usarlo cuando no se trata de operaciones riesgosas que deben atraparse ...
para una mayor comprensión, ver:
Sospecho que le gustaría detectar errores que no están marcados explícitamente con "tiros".
Esto no tiene sentido. No puede capturar más que los errores que están marcados explícitamente con "tiros". Por lo tanto, esta advertencia es válida.
Para este ejemplo, si se ejecuta, fatal error: Index out of range
se producirá fatal error: Index out of range
. Esto es un error de tiempo de ejecución, y no puedes atraparlo.
Para este ejemplo, debe verificar el tamaño de los elementos como este, en lugar de realizar el manejo de errores de prueba-captura: