Mes petites questions de débutants

JoJoSJoJoS Membre
14:22 modifié dans API AppKit #1
Bonjour, Bonjour !!!

J'aimerais vous posez quelques questions...
Je me "remet" au développement Cocoa / Obj-c après 5 mois pendant lesquels je n'avais plus d'ordi jusqu'à  l'arrivé de mon messie : le livreur tnt qui m'a déposer mon iMac !!.

1)
Je voudrais savoir pourquoi mes applications, une fois que l'on ferme la fenêtre principale par la "bubble rouge" de fermeture, il m'est impossible de ré-ouvrir cette fenêtre ??
L'application tourne toujours, mais je n'ai aucun moyen d'afficher à  nouveau ma fenêtre. Je viens tout juste de constater ce problème (qui se retrouve d'ailleurs sur une ancienne appli...).
Il me semble pourtant avoir lu, je ne sais plus où dans la doc d'apple, que le fait de cliquer sur l'icône de l'application dans le Dock affichait obligatoirement une fenêtre (un document si "document-based", la "main-frame" sinon...).
Et en effet, cela fonctionne très bien en créant une application de type "document-based"...

2)
Ma deuxième question n'a rien à  voir du tout avec la première. En faite, je me la pose à  cause de ce fichu livre "Cocoa par la pratique" que, apparemment, beaucoup possède. (Il faut dire que c'est le seul dispo en français...).
Mon problème survient au chapitre 5, exercice 2, quand il est demander de permettre la suppression de plusieurs lignes... Je n'arrive pas à  trouver la solution...
Voilà  un petit énoncer pour ceux qui n'auraient pas le livre :
Permettre la suppression de plusieurs lignes d'un NSTableView.
Pour cela, l'auteur nous informe la présence de la méthode selectedRowEnumerator qui renvoit une énumération d'index des lignes sélectionnées.

Comme un bleu, j'ai fait une boucle sur les éléments de l'énumération, et je supprime chaque ligne suivant l'index que j'obtiens. Mais comme prévu, ça plante car problème d'index hors tableau...
Bref je bloque... :-\\ Si quelqu'un aurait une solution ?
Par contre j'ai lu dans la doc que cette méthode était dépréciée depuis 10.3, et qu'il fallait désormais utiliser selectedRowIndexes...
Mais c'est encore pire... Je ne comprends pas comment faire non plus avec un NSIndexSet.
D'ailleurs, je n'arrive pas à  comprendre comment manipuler un NSIndexSet.

Merci !!!
«1

Réponses

  • psychoh13psychoh13 Mothership Developer Membre
    14:22 modifié #2
    Bon pour ta deuxième question, il faut en fait que tu comptes le nombre d'objets que tu as supprimé dans ton array et l'index qu'on te donne tu lui enlèves le nombre d'éléments supprimés.
    Ou alors tu procèdes à  l'envers, tu supprimes d'abord le dernier, puis ensuite le précédent, jusqu'au premier. Les index à  supprimer ne seront donc pas changer. Pour NSIndexSet, avec la deuxième technique, tu dois utiliser pour l'initialisation -[NSIndexSet lastIndex] puis la méthode -[NSIndexSet indexLessThanIndex:] sachant que ces méthodes retournent NSNotFound s'il n'y a plus rien, tu peux utiliser ça comme condition de sortie.

    Voilà  ce que ça peut donner :

    unsigned index;<br />NSIndexSet *indexes = [tableView selectedRowIndexes];<br />for(index = [indexes lastIndex];<br />&nbsp; &nbsp; index != NSNotFound;<br />&nbsp; &nbsp; index = [indexes indexLessThanIndex:index])<br />{<br />&nbsp; &nbsp; // supression<br />}
    


    Voilà ...
  • schlumschlum Membre
    octobre 2007 modifié #3
    dans 1193226052:

    1)
    Je voudrais savoir pourquoi mes applications, une fois que l'on ferme la fenêtre principale par la "bubble rouge" de fermeture, il m'est impossible de ré-ouvrir cette fenêtre ??
    L'application tourne toujours, mais je n'ai aucun moyen d'afficher à  nouveau ma fenêtre. Je viens tout juste de constater ce problème (qui se retrouve d'ailleurs sur une ancienne appli...).
    Il me semble pourtant avoir lu, je ne sais plus où dans la doc d'apple, que le fait de cliquer sur l'icône de l'application dans le Dock affichait obligatoirement une fenêtre (un document si "document-based", la "main-frame" sinon...).
    Et en effet, cela fonctionne très bien en créant une application de type "document-based"...


    Tu as dû mal lire... D'ailleurs pour les "document-based" on peut désactiver cette création de document vide automatique.
    Pour réafficher la fenêtre quand l'application devient active, il faut implémenter "applicationWillBecomeActive" ou "applicationDidBecomeActive" dans le delegate de l'application (ou gérer ça avec les notifications "NSApplicationWillBecomeActiveNotification", "NSApplicationDidBecomeActiveNotification")

    2)
    Ma deuxième question n'a rien à  voir du tout avec la première. En faite, je me la pose à  cause de ce fichu livre "Cocoa par la pratique" que, apparemment, beaucoup possède. (Il faut dire que c'est le seul dispo en français...).
    Mon problème survient au chapitre 5, exercice 2, quand il est demander de permettre la suppression de plusieurs lignes... Je n'arrive pas à  trouver la solution...
    Voilà  un petit énoncer pour ceux qui n'auraient pas le livre :
    Permettre la suppression de plusieurs lignes d'un NSTableView.
    Pour cela, l'auteur nous informe la présence de la méthode selectedRowEnumerator qui renvoit une énumération d'index des lignes sélectionnées.

    Comme un bleu, j'ai fait une boucle sur les éléments de l'énumération, et je supprime chaque ligne suivant l'index que j'obtiens. Mais comme prévu, ça plante car problème d'index hors tableau...
    Bref je bloque... :-\\ Si quelqu'un aurait une solution ?
    Par contre j'ai lu dans la doc que cette méthode était dépréciée depuis 10.3, et qu'il fallait désormais utiliser selectedRowIndexes...
    Mais c'est encore pire... Je ne comprends pas comment faire non plus avec un NSIndexSet.
    D'ailleurs, je n'arrive pas à  comprendre comment manipuler un NSIndexSet.


    Faut traiter la liste à  l'envers... (cf. "reverseObjectEnumerator", c'est la méthode la plus efficace)
  • schlumschlum Membre
    14:22 modifié #4
    Ah oui, et pour 10.4 et >, il y a encore plus efficace :

    "selectedRowIndexes"

    Puis "removeObjectsAtIndexes" de NSMutableArray

    En 1 ligne...
  • psychoh13psychoh13 Mothership Developer Membre
    14:22 modifié #5
    Ah oui c'est vrai j'avais oublié cette méthode :D

    Même une seule ligne :

    [myArray removeObjectsAtIndexes:[tableView selectedRowIndexes]];
    


    :D

    [EDIT] grillé...
  • JoJoSJoJoS Membre
    14:22 modifié #6
    Ah oui, et pour 10.4 et >, il y a encore plus efficace :

    "selectedRowIndexes"

    Puis "removeObjectsAtIndexes" de NSMutableArray

    En 1 ligne...


    Cool merci !! Je n'avais même pas vu cette méthode !!!
    Du coup ça simplifie grandement le problème !

    Tu as dû mal lire... D'ailleurs pour les "document-based" on peut désactiver cette création de document vide automatique.
    Pour réafficher la fenêtre quand l'application devient active, il faut implémenter "applicationWillBecomeActive" ou "applicationDidBecomeActive" dans le delegate de l'application (ou gérer ça avec les notifications "NSApplicationWillBecomeActiveNotification", "NSApplicationDidBecomeActiveNotification")


    Arf, j'ai du mal comprendre ce que je lisais...
    Donc c'est tout à  fait normal que mon appli ne se ré-ouvre pas.

    Si j'ai bien compris, je dois implementer la méthode delegate applicationWillBecomeActive de la manière suivante :
    <br />if(![[NSApp mainWindow] isVisible]){<br />&nbsp;  [[NSApp mainWindow] display];<br />}<br />
    

    ??
  • schlumschlum Membre
    14:22 modifié #7
    Plutôt que "display", utilise "makeKeyAndOrderFront"...
  • JoJoSJoJoS Membre
    octobre 2007 modifié #8
    Ok !!
    Bon, je test ces modifications ce soir !
    Merci !!

    Super, ca fonctionne niquel pour removeObjectsAtIndexes !!
    Par contre je n'ai pas encore tester pour l'ouverture de la fen
  • JoJoSJoJoS Membre
    octobre 2007 modifié #9
    J'ai une autre petite question :
    Les NSLog que l'on met un peu partout, est ce qu'ils sont supprimés lors de la compilation en mode release ou ils restent dans le code et c'est à  nous de les supprimer ?

    (Normalement il y a une suite ici... Mais j'ai l'impresson que Safari 3 version Windaube ne veut pas l'afficher... Ca fait déjà  3 fois que je le réecris, donc j'abandonne, tant pis pour la suite...)
  • schlumschlum Membre
    14:22 modifié #10
    Faut éviter de mettre des NSLog un peu partout...
    Ca reste en Release et ça écrit dans console.log
  • ChachaChacha Membre
    14:22 modifié #11
    dans 1193391488:

    Faut éviter de mettre des NSLog un peu partout...
    Ca reste en Release et ça écrit dans console.log


    Une petite discussion intéressante à  ce sujet :
    http://www.objective-cocoa.org/forum/index.php/topic,2172.0.html

    +
    Chacha
  • JoJoSJoJoS Membre
    14:22 modifié #12
    Bon, bin je ferai attention avec les NSLog...
    C'est tout de même dommage qu'il n'y ai rien de prévue. Il me semble qu'en .net il y a un objet Debug qui permet l'écriture sur la console uniquement en mode debug.

    J'ai encore une question :

    Peut on utiliser les tableaux c ???
    Parce que j'ai essayer cela : int[] et ça ne fonctionne pas.
    Bon, en réfléchissant un peu j'ai trouvé cela logique puisque les [ sont la pour les messages.
    Je ne suis pas hyper calé en c, mais il me semble que l'on peut également déclarer un tableau de cette façon : int*

    Mais dans ce cas, comment l'initialiser, et l'interroger ??

    En tout cas, merci beaucoup pour votre aide !!!

    ps: j'ai oublié de préciser dans les signature de méthodes...
  • CéroceCéroce Membre, Modérateur
    14:22 modifié #13
    Essaie:

    int monTableau[22];
    


    Ca devrait mieux marcher.

    Tout le C, sans exception, je crois, fonctionne en ObjC.
  • psychoh13psychoh13 Mothership Developer Membre
    octobre 2007 modifié #14
    Pour les NSLog tu peux facilement contourner le problème en utilisant le préprocesseur...

    Par exemple, dans Xcode, tu ouvres un inspécteur de ton projet, (commande + option + I) tu cliques sur Build, tu choisis la configuration Debug et tu recherches "Preprocessor".
    Tu devrais avoir quelque chose du genre "Preprocessor Macros", écrit simplement DEBUG dedans.
    Ensuite, dans ton code, tu fais un fichier MyDefines.h où tu mettras tes macros de debug. Pour intégrer NSLog tu peux par exemple mettre :

    #ifdef DEBUG<br />#define NSLOG(format, ...) NSLog(format)<br />#else<br />#define NSLOG(format, ...)<br />#endif
    


    Si tu ne mets pas les points de suspension ça ne marchera pas, puisque NSLog() peut prendre un nombre infini de paramètres.

    Avec ce code que je t'ai donné au-dessus, tu pourras écrire ceci dans ton code :

    NSLOG(@&quot;Method : -[%@ %s]&quot;, [self class], _cmd);
    


    Pour afficher la méthode appelée et la classe de l'objet qui a reçu le message. Après le passage du préprocesseur en mode DEBUG tu auras le code normal :

    NSLog(@&quot;Method : -[%@ %s]&quot;, [self class], _cmd);
    


    En mode Release tu auras simplement ceci :

    ;
    


    Ce qui ne pose aucun problème au compilateur, tu peux donc faire des appels à  NSLog() de façon à  avoir toutes les informations que tu souhaites lors du débogage sans pour autant surcharger l'application en mode normal.

    En ce qui concerne les tableaux. Objective-C est un stricte surensemble du C, donc tout ce qui est possible en C est possible en Objective-C. Le compilateur fait très bien la différence entre un appel de message : [receveur message] et un tableau : int tab[5], et heureusement d'ailleurs !

    À mon avis tu t'es simplement trompé dans l'écriture de ton tableau. Pour finir, oui on peut "remplacer" un tableau d'entier par un pointeur sur entier, dans le premier cas il s'agira d'un tableau statique, dans le deuxième cas ce sera plutôt un tableau dynamique.

    Donc dans la signature d'une méthode c'est le même principe qu'en C pour les fonctions. Tu peux mettre un tableau en paramètre mais tu ne peux pas retourner de tableau.

    - (void)methode:(int&#91;])tab; // juste<br />- (int&#91;])methode; // faux
    
  • schlumschlum Membre
    14:22 modifié #15
    dans 1193747354:
    Peut on utiliser les tableaux c ???
    Parce que j'ai essayer cela : int[] et ça ne fonctionne pas.
    Bon, en réfléchissant un peu j'ai trouvé cela logique puisque les [ sont la pour les messages.
    Je ne suis pas hyper calé en c, mais il me semble que l'on peut également déclarer un tableau de cette façon : int*


    À la définition d'un tableau, soit tu ne précises pas la taille et tu le remplis, soit tu précises la taille.

    int tabl1&#91;] = {1,2,3};<br />int tabl2[3];
    
  • schlumschlum Membre
    octobre 2007 modifié #16
    dans 1193749228:

    #ifdef DEBUG<br />#define NSLOG(format, ...) NSLog(format)<br />#else<br />#define NSLOG(format, ...)<br />#endif
    



    Y a un problème là , tu zappes tous les arguments optionnels, non ?

    J'aurais dit :
    #define NSLOG(format, ...) NSLog(format,__VA_ARGS__)
    
  • psychoh13psychoh13 Mothership Developer Membre
    14:22 modifié #17
    Non pas du tout, j'ai testé, ça marche justement comme ça. Le préprocesseur va remplacer "format" dans NSLog() par format dans le NSLOG() et tous les arguments qui suivent.
  • JoJoSJoJoS Membre
    14:22 modifié #18
    Génial t'as méthode psychoh !!!!
    C'est quand même génial ces instructions que l'on peut donner au preprocesseur !

    Par contre c'est étrange pour les tableaux...
    Mon erreur erreur venait certainement de là  : - (int[])methode; // faux
    Donc si j'ai bien compris, il faut une signature comme cela : - (int*)methode;

    À la définition d'un tableau, soit tu ne précises pas la taille et tu le remplis, soit tu précises la taille.

    Bin en fait, j'ai une classe qui a des attributs qui sont des tableaux de int.
    Mais je ne sais pas à  l'avance la taille des ces tableaux.
  • schlumschlum Membre
    octobre 2007 modifié #19
    dans 1193755676:

    Non pas du tout, j'ai testé, ça marche justement comme ça. Le préprocesseur va remplacer "format" dans NSLog() par format dans le NSLOG() et tous les arguments qui suivent.


    Si tu le dis...
    Moi j'ai préprocessé ça :
    #define NSLOG(format, ...) NSLog(format)<br /><br />int main(int argc, char *argv&#91;])<br />{<br />	NSLOG(@&quot;Method : -[%@ %s]&quot;, [self class], _cmd);<br />    return NSApplicationMain(argc,  (const char **) argv);<br />}
    


    Et j'obtiens ça :
    # 1 &quot;/Users/schlum/Desktop/TestMacro/main.m&quot;<br /># 1 &quot;/Users/schlum/Desktop/TestMacro//&quot;<br /># 1 &quot;&lt;built-in&gt;&quot;<br /># 1 &quot;&lt;command line&gt;&quot;<br /># 1 &quot;/Users/schlum/Desktop/TestMacro/main.m&quot;<br /><br /><br />int main(int argc, char *argv&#91;])<br />{<br /> NSLog(@&quot;Method : -[%@ %s]&quot;);<br />    return NSApplicationMain(argc, (const char **) argv);<br />}
    


    Mais bon, je dis ça, je dis rien  ;)

    Si "__VA_ARGS__" existe, c'est pas pour rien... ???

    [Edit] Bon, évidemment, quand je rajoute __VA_ARGS__, ça ne passe qu'au préprocess, la compilation ne se fait pas, parce que [self class] dans le main... :P
  • psychoh13psychoh13 Mothership Developer Membre
    14:22 modifié #20
    T'as raison pour le __VA_ARGS__, j'avais testé avec un seul argument, alors il a du chercher le %s n'importe où... Enfin toujours est-il que cette technique marche, donc le code à  mettre pour que ça fonctionne c'est :

    #ifdef DEBUG<br />#define NSLOG(format, ...) NSLog(format, __VA_ARGS__)<br />#else<br />#define NSLOG(format, ...)<br />#endif
    


    Et là  t'auras be beaux NSLog() rien que pour le debug. :D
  • schlumschlum Membre
    14:22 modifié #21
    Je rappelle également que pas mal de techniques de log ont été abordées ici  ;)

    http://www.objective-cocoa.org/forum/index.php/topic,2172.0.html

    Et je reporte encore votre attention sur __FILE__ et __LINE__, vraiment super pratique pour savoir retrouver immédiatement où a eu lieu un log  :P

    Par exemple :
    #define NSLOG(format, ...) NSLog(@&quot;%s:%d - %@&quot;,__FILE__,__LINE__,[NSString stringWithFormat:format,__VA_ARGS__])
    

    <3 <br />
    (houlà , pas testé, j'espère que ça fonctionne :D)
  • psychoh13psychoh13 Mothership Developer Membre
    14:22 modifié #22
    Apparemment ça marche :D
  • schlumschlum Membre
    14:22 modifié #23
    Ah, apparemment il faut mettre "##__VA_ARGS__", je ne sais plus pour quelle obscure raison  ???
  • JoJoSJoJoS Membre
    14:22 modifié #24
    Ouais, j'ai déjà  été voir ce fils de discussion suite au lien de Chacha, mais j'avoue ne rien y avoir compris...

    Vous les trouvez où ces variables du preprocesseur ?? (__VA_ARGS__, __FILE__, ...).
  • psychoh13psychoh13 Mothership Developer Membre
    14:22 modifié #25
    Regarde ce lien par exemple : http://www.cs.utah.edu/dept/old/texinfo/cpp/cpp_toc.html#SEC12

    Pour ce qui est de ##, chez moi j'en ai pas besoin, et le mettre ne change rien... ça signifie la concaténation de deux chaà®nes... Mais l'intérêt je vois pas.
  • AliGatorAliGator Membre, Modérateur
    14:22 modifié #26
    dans 1193749228:

    #ifdef DEBUG<br />#define NSLOG(format, ...) NSLog(format)<br />#else<br />#define NSLOG(format, ...)<br />#endif
    


    Si tu ne mets pas les points de suspension ça ne marchera pas, puisque NSLog() peut prendre un nombre infini de paramètres.
    Heu pas tout à  fait : écrit comme ça, les paramètres optionnels passés à  la macro NSLOG après le paramètre "format" ne seront pas repris lors de l'expansion de la macro ! Il faut utiliser la constante de preprocessing magique __VA_ARGS__ :
    #ifdef DEBUG<br />#define NSLOG(format, ...) NSLog(format , __VA_ARGS__)<br />#else<br />#define NSLOG(format, ...)<br />#endif
    

  • psychoh13psychoh13 Mothership Developer Membre
    14:22 modifié #27
    Désolé, tu as 10 réponses de retard au moins :D
  • 14:22 modifié #28
    Pourquoi tu crois qu'il est écrit "grilleur à  retardement" sous son pseudo?
  • AliGatorAliGator Membre, Modérateur
    14:22 modifié #29
    J'ai pas 10 réponses de retard, j'ai une page de retard, grande nuance  :)beta:
  • Philippe49Philippe49 Membre
    14:22 modifié #30
    dans 1193761349:


    Vous les trouvez où ces variables du preprocesseur ?? (__VA_ARGS__, __FILE__, ...).


    Elles sont inscrites dans la norme du langage C
  • octobre 2007 modifié #31
    dans 1193823084:

    dans 1193761349:


    Vous les trouvez où ces variables du preprocesseur ?? (__VA_ARGS__, __FILE__, ...).


    Elles sont inscrites dans la norme du langage C

    C'est plutôt spécifique à  GCC non?
Connectez-vous ou Inscrivez-vous pour répondre.