Les Exceptions Je suis un peu perdu avec NS_DURING, @try, @throw, @catch

GercofisGercofis Membre
21:47 modifié dans API AppKit #1
Quelqu'un pourrait-il nous donner l'explication pour intaller une exception ? Très peu d'exemple existent, Bref je patauge ... ( bon c'est pas nouveau non plus ! )
NS_DURING, NS_HANDLER, NS_ENDHANDLER, etc...

semblent faire double emploie avec

@try{}, @throw{}, @catch{}

:'( :why?:

Réponses

  • AliGatorAliGator Membre, Modérateur
    mars 2007 modifié #2
    Dis, tu as cherché avant de poster ? Dans la doc Apple y'a tout ce qui faut (comme souvent d'ailleurs).

    Donc la première chose à  faire c'est d'ouvrir la doc Apple et chercher dedans les sujets qui parlent des Exceptions en Objective-C. Oh miracle, on y trouve ceci et aussi ceci, ça alors, quelle surprise... les as-tu lus ?

    J'imagine que non, sinon tu aurais vu des remarques comme (pour @try, @catch, ...)
    Important: The compiler directives discussed below were introduced in Mac OS X v10.3. An application that uses these directives for exception handling cannot run on earlier versions of the operating system.
    ou (pour NS_DURING, etc) :
    Important: The exception macros are a legacy mechanism that should only be used when binary compatibility with versions of of the operating system prior to Mac OS X v10.3 is a concern.
  • GercofisGercofis Membre
    21:47 modifié #3
    J'ai du mal a comprendre qu'on réponde a une question par une question ?

    Il me semble que c'est un forum Français ?

    Et si je parlais l'anglais je n'aurais pas forcément besoin de poser des questions ici ?

    En plus de cela vu ma difficulté a capter ( ça vient peut-être de moi ) ce sysème des exceptions, dont personne ne parle, je pense aussi que ça peut intéressé d'autres, qui eux n'osent peut-être pas poser ce genre de question...

    Ne ditons pas le ridicule ne tue pas !!
  • laurrislaurris Membre
    21:47 modifié #4
    Dans le @try, tu testes le message obj-c; dans le @catch(exception) tu fais quelque chose avec exception; dans le @finally tu finalise.
    A noter que @catch n'est appelé qu'en cas d'exception et @finally dans tous les cas.

    Quant à  @trow, je ne ne vois pas bien à  quoi il sert vu qu'on peut obtenir la même chose avec [exception raise].
  • GercofisGercofis Membre
    21:47 modifié #5
    Je pensais bien a quelque chose comme ça...

    Mais du coup a quoi sert NS_DURING, NS_HANDLER, etc...

    C'est la même chose et ce sont des macros ? ou est-ce plus fait pour un emploi en local ?
  • laurrislaurris Membre
    21:47 modifié #6
    dans 1173384955:

    Mais du coup a quoi sert NS_DURING, NS_HANDLER, etc...


    Là  dessus, sans vouloir enfoncer le clou, tu devrais relire la réponse de Ali. Sachant que "legacy" veut dire en gros: vieux machin.
  • GercofisGercofis Membre
    21:47 modifié #7
    dans 1173385167:

    dans 1173384955:

    Mais du coup a quoi sert NS_DURING, NS_HANDLER, etc...
    Là  dessus, sans vouloir enfoncer le clou, tu devrais relire la réponse de Ali. Sachant que "legacy" veut dire en gros: vieux machin.
    Ok merci, bien sûr que je ne savais pas, j'avais ça dans le livre Objective-C, et je pense que c'est ça qui me perturbait finalement...
    Mais pour qu'un clou tienne il faut l'enfoncer...
    En tous cas merci...
  • schlumschlum Membre
    21:47 modifié #8
    Tiens, j'en étais resté aux macros  :)

    C'est quoi l'apport de @finally ? J'ai pas réussi à  déterminer malgré une lecture attentive des pages...

    Apparemment, ça :
    @try {<br />	// Blabla try<br />}<br />@catch(NSException *error) {<br />	// Blabla catch<br />}<br />// Blabla finally<br />// Blabla
    


    et ça :
    @try {<br />	// Blabla try<br />}<br />@catch(NSException *error) {<br />	// Blabla catch<br />}<br />@finally {<br />	// Blabla finally<br />}<br />// Blabla
    


    C'est pareil non ? Malgré des tests, je n'ai pas réussi à  déterminer la différence entre les deux  :o
  • mars 2007 modifié #9
    dans 1173379649:

    J'ai du mal a comprendre qu'on réponde a une question par une question ?

    Il a eu la gentillesse de consacrer une partie de son temps libre pour répondre à  ta question, de rechercher et recopier pour toi les extraits pertinents dans la documentation. Alors je te prierais de te montrer plus courtois envers lui...

    Y en a qui sont gonflés quand même.

    dans 1173379649:
    Il me semble que c'est un forum Français ?

    C'est en effet un forum francophone, mais vu que:
    1. l'anglais est incontournable pour qui veut progresser en cocoa;
    2. les membres qui répondent aux questions le font sur leur temps libre et de ce fait on ne peut pas exiger d'eux qu'ils traduisent des textes écrits dans une langue incontournable pour le domaine qui est l'objet de ce forum;
    3. il existe des outils de traduction automatique pour ceux qui ne comprennent vraiment pas l'anglais (qui devraient être une minorité, à  cause du point 1.);

    les réponses contenant des extraits de texte écrits en anglais sont tolérées et sont même préférées à  pas de réponse du tout. De même que nous n'exigeons pas des membres qu'ils traduisent les pages web qu'ils renseignent dans des réponses.

    dans 1173379649:

    Et si je parlais l'anglais je n'aurais pas forcément besoin de poser des questions ici ?

    On ne te demande pas de parler anglais, ni même de comprendre un film américain en version originale sans sous-titre. On te demande de comprendre un texte écrit en anglais technique.

    Si tu veux pas apprendre le peu d'anglais nécessaire à  la compréhension d'un document technique, c'est ton problème, mais ne t'en sers pas comme une excuse pour ne pas chercher et nous demander de faire ce boulot à  ta place ou ignorer les réponses qui te sont proposées.
  • mars 2007 modifié #10
    dans 1173391785:

    C'est quoi l'apport de @finally ? J'ai pas réussi à  déterminer malgré une lecture attentive des pages...


    C'est pareil dans l'exemple que tu donnes. Mais dans ce genre de cas:
    [tt]@try {
    return;
    }
    @finally {
    NSLog(@finally);
    }[/tt]

    ça ne l'est pas. Tu as la garantie que le code inclus dans le bloc @finally sera exécuté quoi qu'il arrive. Utile pour la gestion mémoire. Euh "quoi qu'il arrive" est peut être un peu excessif, mais bon, tu comprends l'idée.
  • schlumschlum Membre
    21:47 modifié #11
    dans 1173394419:

    dans 1173391785:

    C'est quoi l'apport de @finally ? J'ai pas réussi à  déterminer malgré une lecture attentive des pages...


    C'est pareil dans l'exemple que tu donnes. Mais dans ce genre de cas:
    [tt]@try {
    return;
    }
    @finally {
    NSLog(@finally);
    }[/tt]

    ça ne l'est pas. Tu as la garantie que le code inclus dans le bloc @finally sera exécuté quoi qu'il arrive. Utile pour la gestion mémoire. Euh "quoi qu'il arrive" est peut être un peu excessif, mais bon, tu comprends l'idée.

    OK, donc le "finally" sert à  "clore" un "try" quand on ne veut pas mettre de "catch"  :) (le compilateur gueule avec un "try" tout seul...)
    Merci  ;)
  • AliGatorAliGator Membre, Modérateur
    21:47 modifié #12
    dans 1173398635:
    OK, donc le "finally" sert à  "clore" un "try" quand on ne veut pas mettre de "catch"  :) (le compilateur gueule avec un "try" tout seul...)
    Heu non pas tout à  fait (voire pas du tout en fait :D)

    Le @finally permet de mettre du code qui sera executé de toute façon, qu'il y ait eu une exception ou pas. Utile pour la gestion mémoire comme le dit Renaud.

    Par exemple :
    -(BOOL)testMethod<br />{<br />&nbsp; A *a = [[A alloc] init];<br />&nbsp; B *b = [[B alloc] init];<br /><br />&nbsp; @try {<br />&nbsp; &nbsp; if ([a doSomething])<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp;  if ([a hasError])<br />&nbsp; &nbsp; &nbsp; &nbsp;  return NO;<br />&nbsp; &nbsp; &nbsp;  if (![b isReady])<br />&nbsp; &nbsp; &nbsp; &nbsp;  return NO;<br />&nbsp; &nbsp; &nbsp;  if (![b doSomethingElse])<br />&nbsp; &nbsp; &nbsp; &nbsp;  return NO;<br />&nbsp; &nbsp; } else {<br />&nbsp; &nbsp; &nbsp; return NO;<br />&nbsp; &nbsp; }<br />&nbsp; }<br />&nbsp; @catch (NSException *exception)<br />&nbsp; {<br />&nbsp; &nbsp; NSLog(@&quot;testMethod : %@: %@&quot;, [exception name], [exception&nbsp; reason]);<br />&nbsp; }<br />&nbsp; @finally<br />&nbsp; {<br />&nbsp; &nbsp; [a release];<br />&nbsp; &nbsp; [b release];<br />&nbsp; }<br />&nbsp; return YES;<br />}<br />
    
    Ici dans ce code je retourne NO s'il y a eu un problème quelquepart dans le code. Si je n'avais pas le @finally, il faudrait que je répète les lignes [tt][a release][/tt] et [tt][b release][/tt] à  chaque fois avant un [tt]return NO;[/tt] pour libérer la mémoire avant de sortir. Ca fait des répétitions de code un peu inutiles.

    Bon certes je pourrais mettre a et b en autorelease, mais bon c'est pour l'exemple.
  • schlumschlum Membre
    21:47 modifié #13
    Ah OK, j'avais raté le "return" au-dessus    :fouf):
    Merci  ;)
  • mars 2007 modifié #14
    Bon certes je pourrais mettre a et b en autorelease, mais bon c'est pour l'exemple.


    L'exemple que tu donnes est peu probable en fait: si les méthodes appellées génèrent une exception, le return qui leur est associé ne sera pas exécuté, mais le controle passera directement dans le code @catch ...pour finalement aboutir à  un return YES. Je reconnais aussi que mon exemple était un peu simpliste, son but était de montrer que le code de ce bloc était exécuté même dans des conditions où il n'aurait pas été exécuté normalement.

    Un exemple plus réaliste aurait été:
    [tt]a = [AClass  new];
    @try {
    [a doSomething];
    }
    @catch (NSException *e) {
    NSLog(@Something bad happened);
    return NO;
    }
    @finalize {
    // La directive @finalize permet d'éviter ici une redondance
    // au niveau du post traitement
    [a release];
    }
    ...[/tt]

    Bon ce cas en pratique n'est pas souvent rencontré, mais il en est un autre qui est du ressort des "nested exceptions" et qui lui est plus fréquent: on recrée une nouvelle exception dont le texte est plus approprié à  la fonction exécutée, qu'on renvoie alors dans le système de gestion des exceptions. Et dans quel cas, la fonction courante perd aussi le contrôle et donc il peut en résulter des fuites mémoires sans le @finalize. C'est le cas qui est présenté dans la doc.
  • schlumschlum Membre
    mars 2007 modifié #15
    Ouep, c'est juste le fait que ça passait dedans même avec un "return" ou un "throw" au niveau du catch que j'avais raté.
    Effectivement, fort utile pour les "nested exceptions" ! (même si on peut s'en tirer sans avec des redondances...)
  • psychoh13psychoh13 Mothership Developer Membre
    septembre 2007 modifié #16
    dans 1173435855:
    L'exemple que tu donnes est peu probable en fait: si les méthodes appellées génèrent une exception, le return qui leur est associé ne sera pas exécuté, mais le controle passera directement dans le code @catch ...pour finalement aboutir à  un return YES.


    Bah non justement, quand une exception est levée, tout ce qui est après le @try et hors du @catch utilisé ou du @finally ne sera pas exécuté, c'est pour ça qu'il y a le @finally, la fin de la fonction n'est pas exécutée. Donc il faudrait faire ce genre de truc :

    Donc je pense qu'il vaudrait mieux faire ce genre de code

    -(BOOL)testMethod<br />{<br />&nbsp; &nbsp; A *a = [[A alloc] init];<br />&nbsp; &nbsp; B *b = [[B alloc] init];<br /><br />&nbsp; &nbsp; @try<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; if ([a doSomething])<br />&nbsp; &nbsp; &nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Si l&#39;une de ces méthodes lèvent une exception, leur return NO; ne sera pas exécuté<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ([a hasError])<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return NO;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (![b isReady])<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return NO;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (![b doSomethingElse])<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return NO;<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; else<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return NO;<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; @catch (NSException *exception)<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; NSLog(@&quot;testMethod : %@: %@&quot;, [exception name], [exception&nbsp; reason]);<br />&nbsp; &nbsp; &nbsp; &nbsp; // Si une exception est levée, ce qui suit le @try ne sera pas exécuté,<br />&nbsp; &nbsp; &nbsp; &nbsp; // il faut donc mettre le return NO; quelque part si on ne lève pas d&#39;autre exception<br />&nbsp; &nbsp; &nbsp; &nbsp; return NO;<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; @finally<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; // Qu&#39;une exception ou pas soit levée, le bloc @finally est exécuté<br />&nbsp; &nbsp; &nbsp; &nbsp; // donc les objets recevront toujours leur message -release<br />&nbsp; &nbsp; &nbsp; &nbsp; [a release];<br />&nbsp; &nbsp; &nbsp; &nbsp; [b release];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; // Ce return sera exécuté SI ET SEULEMENT SI aucune exception n&#39;aura était levée<br />&nbsp; &nbsp; return YES;<br />}<br />
    


    Ensuite pour répondre à  la question à  savoir : à  quoi sert l'instruciton @throw alors qu'on peut écrire [monException raise] ?
    Il existe pour deux raisons essentiellement, d'abord pour permettre l'écriture, plus en rapport avec les autres instructions et moins lourds en terme d'envoi de message, de ce genre de truc : @throw [NSException exceptionWithName: NSGenericException reason: @It crashed man ! userInfo: nil];
    Mais aussi et surtout parce que tu peux lever autre chose que des objets héritant de NSException. La forme canonique de l'utilisation des exceptions c'est ça :

    -(void)maMethode<br />{<br />&nbsp; &nbsp; // Code<br />&nbsp; &nbsp; @try<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; // Code susceptible de lever une exception<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; @catch (MySpecificException *e)<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; // Traitement spécifique à  l&#39;exception<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; @catch (NSException *e)<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; // Traitement pour tout autre type d&#39;exception<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; @catch (id *e)<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; // Traitement pour tout autre type d&#39;objet<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; @finally<br />&nbsp; &nbsp; {<br />&nbsp; &nbsp; &nbsp; &nbsp; // Code à  exécuter dans tous les cas<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; // Code à  exécuter si tout s&#39;est bien passé<br />}
    


    Notez que si après le finally il y a des traitements à  faire sur les objets si tout s'est bien passé, on peut envoyer le message -autorelease plutôt que -release pour éviter de bousiller le code qui suit.

    Il faut aussi remarquer que l'instruction @throw peut permettre aussi au compilateur de faire des optimisations.
    Pour ceux qui se poseraient la question, à  savoir : comment on fait pour connaà®tre la raison de l'exception lorsqu'il s'agit d'un objet de type id quelconque ?
    Vous pouvez par exemple utiliser la méthode -description qui est disponible à  tous les objets respectant le procotole NSObject, de cette façon :

    NSLog(@&quot;Raised exception : %@&quot;, e);
    


Connectez-vous ou Inscrivez-vous pour répondre.