Quelle est la meilleure façon de lever une exception en objectif-c / cacao?
objective-c
cocoa
exception-handling
Steph Thirion
la source
la source
@throw([NSException exceptionWith…])
approche car elle est plus concise.Un mot de prudence ici. Dans Objective-C, contrairement à de nombreux langages similaires, vous devez généralement éviter d'utiliser des exceptions pour les situations d'erreur courantes qui peuvent se produire en fonctionnement normal.
Documentation d'Apple pour Obj-C 2.0 stipule ce qui suit: "Important: Les exceptions sont gourmandes en ressources dans Objective-C. Vous ne devez pas utiliser d'exceptions pour le contrôle de flux général, ou simplement pour signifier des erreurs (comme un fichier non accessible)"
Documentation de gestion des exceptions conceptuelles d'Apple explique la même chose, mais avec plus de mots: "Important: vous devez réserver l'utilisation d'exceptions pour la programmation ou les erreurs d'exécution inattendues telles que l'accès à la collection hors limites, les tentatives de mutation d'objets immuables, l'envoi d'un message non valide et la perte de la connexion au serveur Windows. En règle générale, vous vous occupez de ce type d'erreurs avec des exceptions lors de la création d'une application plutôt qu'au moment de l'exécution. [.....] Au lieu d'exceptions, les objets d'erreur (NSError) et le Le mécanisme de remise des erreurs Cocoa est le moyen recommandé de communiquer les erreurs attendues dans les applications Cocoa. "
Cela s'explique en partie par le respect des idiomes de programmation dans Objective-C (en utilisant des valeurs de retour dans des cas simples et des paramètres de référence (souvent la classe NSError) dans des cas plus complexes), en partie parce que lever et intercepter des exceptions est beaucoup plus cher et enfin (et perplexe le plus important) que les exceptions Objective-C sont un wrapper mince autour des fonctions setjmp () et longjmp () de C, gâchant essentiellement votre gestion prudente de la mémoire, voir cette explication .
la source
Xcode reconnaît les
@throw
instructions comme des points de sortie de fonction, comme lesreturn
instructions. L'utilisation de la@throw
syntaxe évite les avertissements erronés "Le contrôle peut atteindre la fin de la fonction non nulle " que vous pouvez obtenir[NSException raise:…]
.En outre,
@throw
peut être utilisé pour lancer des objets qui ne sont pas de NSException de classe.la source
Concernant
[NSException raise:format:]
. Pour ceux qui viennent d'un arrière-plan Java, vous vous souviendrez que Java fait la distinction entre Exception et RuntimeException. L'exception est une exception vérifiée et RuntimeException n'est pas cochée. En particulier, Java suggère d'utiliser des exceptions vérifiées pour les "conditions d'erreur normales" et des exceptions non vérifiées pour les "erreurs d'exécution causées par une erreur de programmation". Il semble que les exceptions Objective-C devraient être utilisées aux mêmes endroits que vous utiliseriez une exception non vérifiée, et les valeurs de retour de code d'erreur ou les valeurs NSError sont préférées aux endroits où vous utiliseriez une exception vérifiée.la source
Je pense que pour être cohérent, il est plus agréable d'utiliser @throw avec votre propre classe qui étend NSException. Ensuite, vous utilisez les mêmes notations pour essayer finalement catch:
Apple explique ici comment lever et gérer les exceptions: Attraper les exceptions Lancer les exceptions
la source
Depuis ObjC 2.0, les exceptions Objective-C ne sont plus un wrapper pour setjmp () longjmp () de C, et sont compatibles avec l'exception C ++, le @try est "gratuit", mais lever et intercepter des exceptions est beaucoup plus cher.
Quoi qu'il en soit, les assertions (en utilisant NSAssert et la famille de macros NSCAssert) lèvent NSException, et cela est sensé de les utiliser comme états Ries.
la source
Utilisez NSError pour communiquer les échecs plutôt que les exceptions.
Points rapides sur NSError:
NSError permet aux codes d'erreur de style C (entiers) d'identifier clairement la cause racine et, espérons-le, au gestionnaire d'erreurs de surmonter l'erreur. Vous pouvez très facilement encapsuler les codes d'erreur des bibliothèques C comme SQLite dans les instances NSError.
NSError a également l'avantage d'être un objet et offre un moyen de décrire l'erreur plus en détail avec son membre de dictionnaire userInfo.
Mais le meilleur de tous, NSError NE PEUT PAS être lancé, ce qui encourage une approche plus proactive de la gestion des erreurs, contrairement à d'autres langues qui jettent simplement la patate chaude de plus en plus haut dans la pile d'appels, auquel cas elle ne peut être signalée qu'à l'utilisateur et pas traité de manière significative (pas si vous croyez qu'il faut respecter le plus grand principe de la POO en matière d'information qui se cache).
Lien de référence : Référence
la source
Voici comment je l'ai appris de "The Big Nerd Ranch Guide (4th edition)":
la source
userInfo:nil
. :)Vous pouvez utiliser deux méthodes pour déclencher une exception dans le bloc try catch
ou la deuxième méthode
la source
Je pense que vous ne devez jamais utiliser d'exceptions pour contrôler le déroulement normal du programme. Mais des exceptions doivent être levées chaque fois qu'une valeur ne correspond pas à une valeur souhaitée.
Par exemple, si une fonction accepte une valeur, et que cette valeur n'est jamais autorisée à être nulle, alors c'est bien de trow une exception plutôt que d'essayer de faire quelque chose de 'intelligent' ...
Ries
la source
Vous ne devez lever des exceptions que si vous vous trouvez dans une situation qui indique une erreur de programmation et que vous souhaitez arrêter l'application en cours d'exécution. Par conséquent, la meilleure façon de lever des exceptions est d'utiliser les macros NSAssert et NSParameterAssert et de vous assurer que NS_BLOCK_ASSERTIONS n'est pas défini.
la source
Exemple de code pour la casse: @throw ([NSException exceptionWithName: ...
}
En utilisant:
Un autre cas d'utilisation plus avancé:
}
la source
Il n'y a aucune raison de ne pas utiliser les exceptions normalement dans l'objectif C même pour signifier des exceptions aux règles métier. Apple peut dire utiliser NSError qui s'en soucie. Obj C existe depuis longtemps et à un moment donné, TOUTE la documentation C ++ a dit la même chose. La raison pour laquelle le fait de lancer et d'attraper une exception coûte peu est que la durée de vie d'une exception est extrêmement courte et ... c'est une EXCEPTION pour le flux normal. Je n'ai jamais entendu personne dire quoi que ce soit de ma vie, l'homme que cette exception a mis longtemps à être levée et rattrapée.
En outre, il y a des gens qui pensent que l'objectif C lui-même est trop cher et code à la place en C ou C ++. Donc, dire toujours utiliser NSError est mal informé et paranoïaque.
Mais la question de ce fil n'a pas encore été répondue quelle est la meilleure façon de lever une exception. Les moyens de retourner NSError sont évidents.
Il en est de même: [NSException raise: ... @throw [[NSException alloc] initWithName .... ou @throw [[MyCustomException ...?
J'utilise ici la règle cochée / décochée légèrement différemment que ci-dessus.
La vraie différence entre (en utilisant la métaphore java ici) cochée / décochée est importante -> si vous pouvez récupérer de l'exception. Et par récupérer, je veux dire non seulement PAS planter.
J'utilise donc des classes d'exceptions personnalisées avec @throw pour les exceptions récupérables, car il est probable que j'aurai une méthode d'application recherchant certains types d'échecs dans plusieurs blocs @catch. Par exemple, si mon application est un guichet automatique, j'aurais un bloc @catch pour la "WithdrawalRequestExceedsBalanceException".
J'utilise NSException: lever pour les exceptions d'exécution car je n'ai aucun moyen de récupérer à partir de l'exception, sauf pour l'attraper à un niveau supérieur et l'enregistrer. Et il n'y a aucun intérêt à créer une classe personnalisée pour cela.
Quoi qu'il en soit, c'est ce que je fais, mais s'il y a une meilleure manière expressive, j'aimerais aussi savoir. Dans mon propre code, depuis que j'ai arrêté de coder C il y a longtemps, je ne retourne jamais de NSError même si je suis passé par une API.
la source