Comment gérer les erreurs pour les méthodes ou le code qui ne jettent pas explicitement?
Envelopper un bloc do/catch entraîne un avertissement du compilateur:
"'catch' block is unreachable because no errors are thrown in 'do' block"
Venant de l’arrière-plan C #/Java, c’est pour le moins une curiosité. En tant que développeur, je devrais être en mesure de protéger et d’envelopper tout bloc de code dans un bloc Do/catch. Le fait qu'une méthode ne soit pas explicitement marquée par "throw" ne signifie pas que des erreurs ne se produiront pas.
Ce que vous demandez n'est pas possible dans Swift, car Swift ne dispose d'aucune facilité pour gérer les erreurs d'exécution telles que les hors limites, les violations d'accès ou l'échec du déploiement forcé en cours d'exécution. Votre application se terminera si l’une de ces erreurs de programmation graves se produit.
Quelques pointeurs:
Longue histoire: Ne raccourcissez pas la gestion des erreurs dans Swift. Jouez la sécurité, toujours.
Solution de contournement: si vous devez absolument intercepter les erreurs d'exécution, vous devez utiliser des limites de processus pour la protection. Exécuter un autre programme/processus et communiquer à l'aide de tuyaux, de sockets, etc.
Je soupçonne que vous aimeriez intercepter des erreurs qui ne sont pas explicitement marquées par "jette".
Cela n’a aucun sens . Vous ne pouvez intercepter que des erreurs qui sont explicitement marquées par "jette" . Cet avertissement est donc valide.
Pour cet exemple, si fatal error: Index out of range
est exécuté, il se produira . Il s’agit d’une erreur d’exécution et vous ne pouvez pas l’accepter.
Pour cet exemple, vous devriez vérifier la taille des éléments comme ceci, au lieu de gérer les erreurs try-catch:
Il y a une différence entre ERREURS et EXCEPTIONS. Swift ne traite que les erreurs explicitement THROWN et n’a pas de capacité native pour traiter EXCEPTIONS. Comme d'autres l'ont fait remarquer, les erreurs doivent être déclenchées et vous ne pouvez pas attraper ce qui ne l'est pas.
En revanche, Objective-C @ try- @ catch traite de exceptions, et non de errors ,. Certaines méthodes objc peuvent provoquer des exceptions mais ne les déclarent en aucune manière auprès du compilateur. par exemple. FileHandle.write. De telles exceptions sont plus proches de celles de RuntimeException de Java, qui n'a pas besoin d'être déclarée.
Il existe des situations telles que la gestion de fichiers où il serait agréable de gérer proprement exceptions dans Swift et il est possible d’utiliser un encapsuleur Objective-C. Voir http://stackoverflow.com/questions/34956002/how-to-properly-handle-nsfilehandle-exceptions-in-Swift-2-0
Code reproduit ici:
#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 */
Puis appelant de 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
}
Face à une exception levée par une méthode qui ne peut pas lancer. Nous avons découvert que cette exception provenait de la partie objective-c de l’API. Vous devriez donc le saisir à l'ancienne en utilisant objective-c.
Premièrement, créez la classe objective-c qui prend plusieurs blocs dans la méthode init - pour try, catch et finalement.
#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
Dans le fichier .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
Deuxièmement, ajoutez ses en-têtes au fichier d’en-tête de pontage.
#import "ObjcTry.h"
Et utilisez-le dans votre code Swift comme ça:
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)
Comme d'autres l'ont mentionné, vous ne devriez pas intercepter ces erreurs, vous devriez les corriger , mais si vous voulez exécuter plus de code avant la fin du programme, utilisez NSSetUncaughtExceptionHandler
dans AppDelegate
dans applicationdidFinishLaunchingWithOptions
.
La description de la fonction:
Change le gestionnaire d'erreurs de niveau supérieur.
Définit la gestion des erreurs de niveau supérieur fonction où vous pouvez effectuer une journalisation de dernière minute avant le programme se termine.