Bonnes pratiques - Domaines et codes NSError pour votre propre projet / application

114

Il existe un article précédent concernant la configuration de domaines d'erreur pour vos propres frameworks, mais quelle est la meilleure pratique concernant la configuration de domaines d'erreur et de codes d'erreur personnalisés pour votre propre projet / application ?

Par exemple, en supposant que vous travaillez sur une application gourmande en données de base avec de nombreuses validations, devriez-vous simplement vous en tenir aux codes d'erreur de données de base «prêts à l'emploi» (comme NSManagedObjectValidationErrorfrom CoreDataErrors.h) ou devriez-vous créer les vôtres MyAppErrors.het définir des erreurs avec plus de spécificité (c'est-à-dire MyAppValidationErrorInvalidCombinationOfLimbs,?

La création d'un domaine d'erreur personnalisé et d'un ensemble de codes d'erreur peut dissiper considérablement l'ambiguïté de votre code, mais est-ce trop de surcharge à gérer et doit-on s'inquiéter des conflits de numérotation des codes d'erreur? Ou y a-t-il d'autres préoccupations ici?

Neal L
la source

Réponses:

152

J'utilise personnellement un domaine de style DNS inversé. Par exemple:

NSError * myInternalError = [NSError errorWithDomain:@"com.davedelong.myproject" code:42 userInfo:someUserInfo];

La troisième partie du domaine ( @"myproject") est juste utilisée pour différencier les erreurs de ce projet ( "My Project") des erreurs d'un autre projet ( "My Other Project"=> com.davedelong.myotherproject).

Il est un moyen simple de faire en sorte que je ne vais pas entrer en conflit avec les domaines d'erreur de quelqu'un d' autre (si je suis en utilisant le code 3ème partie), à moins que le développeur tente délibérément de mess avec juste moi (que je crois serait très improbable. ..).

En ce qui concerne les conflits de numérotation de code, ne vous inquiétez pas à ce sujet. Tant que les codes sont uniques dans un domaine , vous devriez être OK.

Quant aux erreurs de traduction, c'est à vous de décider. Quoi que vous fassiez, assurez-vous de bien le documenter. Personnellement , je ne fais généralement que transmettre les erreurs générées par le framework au fur et à mesure qu'elles me viennent, car je ne suis jamais sûr de gérer tous les codes et de traduire tous les userInfo en quelque chose de plus spécifique à mon projet. Les cadres pourraient changer et ajouter plus de codes, ou changer la signification des codes existants, etc. Cela m'aide également à identifier plus spécifiquement d'où vient l'erreur. Par exemple, si mon framework StackKit génère une erreur dans le com.stackkitdomaine, je sais que c'est un problème de framework. Cependant, s'il génère une erreur dans le NSURLErrorDomain, je sais que cela provient spécifiquement du mécanisme de chargement d'URL.

Ce que vous pouvez faire est de capturer l'erreur générée par le framework et de l'envelopper dans un nouvel objet d'erreur contenant votre domaine et un code générique, quelque chose comme kFrameworkErrorCodeUnknownou quelque chose, puis placez l'erreur capturée userInfosous le NSUnderlyingErrorKey. CoreData le fait beaucoup (par exemple, si vous essayez d' save:un NSManagedObjectContext, mais vous avez des erreurs d'intégrité des relations, vous aurez un retour simple erreur, mais NSUnderlyingErrorKeycontiendra beaucoup plus d' informations, comme spécifiquement les relations sont mauvaises, etc.).

Dave DeLong
la source
Étant donné qu'Apple utilise également le DNS inversé, il semble approprié que d'autres utilisent également ce style.
Johan Karlsson
36

Je n'ai pas assez de représentants pour commenter, mais pour la réponse acceptée par Dave DeLong, il serait peut-être légèrement préférable d'utiliser à la [[NSBundle mainBundle] bundleIdentifier]place de @"com.myName.myProject". De cette façon, si vous modifiez votre nom ou le nom de votre projet, il sera reflété avec précision.

Connor
la source
4
Bonne idée. Si vous utilisez Swift, vous devriez utiliser l'option non emballée: NSBundle.mainBundle().bundleIdentifier!(si vous savez que l'identifiant du bundle est défini, ce qui, je suppose, sera le plus probable)
Juul
Pourquoi voudriez-vous refléter les changements de nom de projet dans le domaine d'erreur?
zrslv
1
@zrxq Il est certain d'avoir différents domaines d'erreur, mais imaginez que vous avez mal orthographié votre projet ou que vous avez changé votre nom et que vous vouliez qu'il soit reflété partout. Mieux vaut le définir dynamiquement que codé en dur.
Connor le
1
@vare C'est clair, je ne comprends pas vraiment quels avantages pratiques cela apporterait. Je crois comprendre que ces identifiants doivent simplement être uniques dans le contexte de l'application, c'est tout. D'accord, peut-être que vous voulez juste qu'ils soient plus esthétiques, je comprends!
zrslv
1
Ouais, vous soulevez un bon point. Il y a des moments où vous voulez que le domaine soit unique, je suppose ... par exemple, peut-être que si vous créez un SDK ou un pod (cacao), vous voudriez que votre domaine d'erreur reflète d'où il vient, pas celui du projet Nom. EDIT: Je voulais aussi (dans ma réponse) souligner que @ "com.myName.myProject" est identique au bundleIdentifier dans ce cas, que les gens pourraient ne pas savoir.
Connor
4

Comment créer un NSError personnalisé:

Créez d'abord un dictionnaire du message d'erreur

NSDictionary *userInfo = @{   
   NSLocalizedDescriptionKey: NSLocalizedString(@"Unknown Error - Please try again", nil),
   NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"Unknown Error - Please try again", nil),
   NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Unknown Error - Please try again", nil)
                                               };
NSError *error = [NSError errorWithDomain:[[NSBundle mainBundle] bundleIdentifier] 
  code:-58 userInfo:userInfo];

Attribuez ensuite le userInfo au NSDictionary et votre fait.

Mike Zriel
la source