[résolu] NSMutableArray : n'arrive pas a stocker mes objets ?

ShomeiShomei Membre
avril 2010 modifié dans API AppKit #1
Bonsoir,

Au sujet des NS...Arrays, la doc apple dit :

Arrays are ordered collections that can contain any sort of object"the collection does not have to be homogeneous.

Donc, j'imagine qu'on peut y stocker des NSTextFields ? Seulement voilà , je n'y parviens pas. (certainement que je m'y prends mal...)
<br />NSMutableArray* TextFieldsArray = [[NSMutableArray alloc] initWithCapacity:10]; // OU juste alloc, init j&#39;ai tenté les deux<br />NSTextField* TF1 = [[NSTextField alloc] initWithFrame:SaFrame];<br />NSTextField* TF2 = [[NSTextField alloc] initWithFrame:SaFrame];<br />// etc...<br /><br />[MaView addSubview:TF1];<br />[MaView addSubview:TF2];<br />//etc...<br /><br />[TextFieldsArray addObject:TF1]; // ou [TextFieldsArray addObject:[TF1 autorelease]]; puisque TF1 fera recevra d&#39;un retain de l&#39;array<br />[TextFieldsArray addObject:TF2]; // idem<br />// etc...<br />


Jusqu'ici, pas de problème. Les textfields apparaissent correctement dans la vue. Ils sont fonctionnels.
Par contre, le code suivant n'a aucun effet :
<br />[TextFieldsArray makeObjectsPerformSelector:@selector(setStringValue:) withObject:@&quot;Test&quot;];<br />


Alors que le code ci-dessous fonctionne très bien :
<br />[TF1 performSelector:@selector(setStringValue:) withObject:@&quot;Test&quot;];<br />


Pire :
<br />if ([[TextFieldsArray objectAtIndex:1] isKindOfClass:[NSObject class]]) NSLog(@&quot;YUP&quot;);<br />else NSLog(@&quot;Nope&quot;);<br />// Log Nope<br /><br />if ([TF1 isKindOfClass:[NSObject class]]) NSLog(@&quot;YUP&quot;);<br />else NSLog(@&quot;Nope&quot;);<br />// Log YUP<br />


J'ai l'impression que les objets que j'ai ajoutés... n'ont pas été ajoutés. (puisque TF1 fonctionne tres bien alors que [TextFieldsArray objectAtIndex:0]  n'est pas un objet fonctionnel. Ce n'est pas une copie non plus...

La doc apple, au sujet de NSMutableArray dit :

And when you add an object to an Objective-C array, the object isn't copied, but rather receives a retain message before its id is added to the array. When an array is deallocated, each element is sent a release message.

J'ai du louper un épisode. Quelqu'un sait comment faire svp ?

Réponses

  • ShomeiShomei Membre
    16:51 modifié #2
    Ce que je ne comprends pas, c'est :

    1. On ne peut pas stocker nil. Donc, un objet a forcément été ajouté puisque obtenir l'objet at index 0, 1, 2, 3 etc... ne pose pas de probleme.

    2. Pourtant, les objets ne répondent pas aux messages... (et en plus ils ne semblent pas dériver de NSObject...)
  • CéroceCéroce Membre, Modérateur
    16:51 modifié #3
    À mon avis, tu as un problème ailleurs...
    Fais du pas à  pas avec le débogueur, il te permet de voir le contenu du NSMutableArray à  tout moment.
  • AliGatorAliGator Membre, Modérateur
    16:51 modifié #4
    Hello

    Alors :
    1) En effet on ne peut pas stocker "nil" dans un NS...Array. On peut stocker un objet [NSNull null] (qui est un singleton, au passage) si on veut vraiment stocker un objet qui aura comme conotation de ne rien représenter, mais bon, ce n'est pas trop l'objet du message

    2) Par contre c'est étrange que ton tableau ne réponde pas (enfin que les TextFields qu'il y a dedans plutôt) aux messages comme tu t'y attends. Tu es bien sûr de rester dans le même "scope", que tu ne remplis pas ton array à  un moment dans la méthode, et y accède dans une autre méthode où tu aurais par hasard nommé une variable du même nom... ou que tu as une variable d'instance nommée TextFieldsArray et que du coup si tu mets le code tel que tu l'as copié sur le forum, tu masques cette variable en en déclarant une autre du même nom, ...?

    Au passage, je te conseille dès à  présent de prendre les bonnes habitudes concernant les conventions de nommage : les noms de classes commencent par une majuscule, mais les noms de variable par une minuscule (tu aurais dû donc nommer ta variable "textFieldsArray"). Ca n'a pas d'impact direct sur l'exécution du code (quoique, sauf si tu utilises le KVC, mais bon c'est pas le cas ici), mais ça en a un gros sur la lisibilité puisque ce sont des conventions préconisées par Apple et que tout le monde respecte (j'ai failli te faire la remarque comme quoi tu envoyais ton message à  une classe et non un objet...)

    Sinon pour mieux comprendre d'où ça vient, fait carrément un [tt]NSLog(@tableau : %@" , TextFieldsArray);[/tt] qui va t'afficher directement dans le log tous les éléments du tableau, chaque élément s'affichant en général en indiquant de quelle classe il est.
    C'est logique que [tt][TF1 isKindOfClass:[NSObject class]][/tt] soit vrai puisque tous les objets Cocoa dérivent de NSObject. Et que isKindOfClass renvoie vrai si l'objet est de la classe indiquée... ou d'une de ses sous-classes (ça ne teste pas juste la classe directement quoi, ça remonte l'arborescence de classes). Directement avec un [tt]NSLog(@TF1 = %@",TF1)[/tt] tu auras la vraie classe (ou même [tt]NSLog(@classe de TF1 : %@" , [TF1 class] );[/tt] )
  • ShomeiShomei Membre
    16:51 modifié #5
    Merci pour vos réponses.
    Et merci pour l'idée du débug. En l'utilisant, j'ai vu que le problème était ailleurs... Et la source du problème est plutôt tordue...

    En fait, je me suis servi d'une combinaisons de bouttons et de NSLog pour déclencher les actions de mon programme étape par étapes(en changeant la target du boutton dans l'IB a chaque build)
    Bien entendu, le NSLog de la fonction (action) appelée sur mon objet (target) s'exécutait a chaque fois. Mais j'ai mis un moment avant de comprendre que cette fonction appartenait a une autre instance de mon objet que je n'avais jamais allouée... Donc l'array était a nil, ce qui explique qu'on puisse appeler n'importe quelle méthode (genre demander un objet a un index fantaisiste) sans déclencher d'erreur.
    En fait, j'ai même compilé une version du programme dans laquelle je n'allouais jamais la classe. l'action invoquée par le bouton s'exécutait quand même.

    J'ai corrigé cette erreur en définissant le couple target/action dynamiquement. Et le problème est résolu. Désolé pour la question. J'espère que la réponse servira a quelqu'un.

    Pour la suite, je songe a remplacer mes textfields par des cells. (pour des raisons de performance) je vais etudier la question.
    Ma vue est en quelque sorte un control qui gere ses textfields. J'ai plusieurs vues de ce type. Autant que l'utilisateur en souhaite... Peut etre que ma vue pourrait gerer ses cells. Ce qui evite de devoir charger un contexte a chaque fois pour dessiner.

    Conclusion : ne jamais lier un bouton à  une classe qui sera allouée après le démarrage de l'application. (en réponse à  un évènement déclenché par l'utilisateur par exemple)  La méthode sera bien appelée, mais ce ne sera pas celle de votre objet actuel... (et le NSLog ne servira a rien, puisqu'il donnera uniquement l'illusion que tout s'est bien pass´´)

    Au passage, je te conseille dès à  présent de prendre les bonnes habitudes concernant les conventions de nommage : les noms de classes commencent par une majuscule, mais les noms de variable par une minuscule (tu aurais dû donc nommer ta variable "textFieldsArray"). Ca n'a pas d'impact direct sur l'exécution du code (quoique, sauf si tu utilises le KVC, mais bon c'est pas le cas ici), mais ça en a un gros sur la lisibilité puisque ce sont des conventions préconisées par Apple et que tout le monde respecte (j'ai failli te faire la remarque comme quoi tu envoyais ton message à  une classe et non un objet...)


    Merci. Ce genre de conseil est précieux. J'ai galéré tellement longtemps, surtout quand j'appellais des set value for keys... parce que mes variables étaient mal nommées... (genre setMe pour une variable nommée me...) et je ne m'en suis rendu compte qu'en relisant une enieme fois la doc.

    MERCI aussi pour NSLog(@tableau : %@" , TextFieldsArray);
    Tres utile.





  • AliGatorAliGator Membre, Modérateur
    16:51 modifié #6
    Tu as regardé du côté des NSForm ?
    Parce qu'au vu de ta description, j'ai l'impression que tu recrées un peu ce genre de chose déjà  existante, non ?
    Enfin même si ce n'est pas pile la même chose, ça peut être intéressant à  regarder, et voir si ça ne vaut pas le coup de dériver de NSForm pour spécialiser pour ton cas plutôt que de refaire from scratch.
  • ShomeiShomei Membre
    16:51 modifié #7
    Je vais jetter un oeil. Le mot form me plait bien. Merci pour la suggestion.

    Pour en dire un peu plus:
    Le résultat que je souhaite obtenir, c'est une "boite" dans laquelle se trouvent : une grandeur A et une grandeur B variables, des grandeurs C, D, E, etc... constantes. J'ai utilisé le terme de grandeur parce qu'il s'agit d'une valeur avec une unite (ex: 32 cm) et non pas une simple valeur numérique.

    Typiquement, l'utilisateur entre A, B, C, D, E etc...
    A est calculé à  partir de C, D, E, etc... en fonction de B. Mais l'utilisateur peut aussi choisir de préciser B pour obtenir A.

    Donc :

    • J'ai besoin de savoir quand l'utilisateur appuie sur "entree" lors de l'edition d'une valeur pour :
      • Actualiser l'affichage en fonction des dernieres valeurs entrees

      • Si l'utilisateur presse "entree" dans la case A (il vient de modifier A) donc on calcule B. Et inversement. (la derniere case editee definit le sens du calcul.


    • J'ai besoin que A, B, C, etc... soient dans une meme boite, parce que l'utilisateur peut placer plusieurs boites de type semblable ou different dans une meme frame (frame, boite = view, pour le moment) qu'il pourra connecter entre elles pour effectuer un calcul plus complexe
    • Il est aussi souhaitable que les valeurs soient affichees avec leurs unités (par exemple XX cm) mais que seule la valeur XX soit fournie pour effectuer le caclcul. => je compte gérer cela au niveau du modele pour eviter que la vue ne fasse des opérations spécialisees. Mais je suis ouvert aux conseils.


    Tres bonne soirée a tous.
  • ShomeiShomei Membre
    16:51 modifié #8
    J'ai lu la doc de NSForm. C'est intéressant, mais j'aurai intérêt a sérieusement personnaliser la classe pour mes besoins.
    Peut-etre gerer directement les NSFormCell, ou alors tout refiaire. Mis j'aimerais eviter autant que possible d'ecrire trop de code...

    Un Element determinant est l'impression.
    Actuellement, mes NSTextFields, de police 12.0 je crois, sortent en géant a l'impression (enfin, sur la preview pdf). J'aimerais éviter d'avoir a modifier les polices. (d'autant plus que ces objets sont destinés a être intégrés dans un traitement de texte...)

    Est-il possible de paramétrer la vue pour obtenir un resultat plus correct ? (sans perdre le benefice de pouvoir utiliser centerScanRect ou NSFrameRectWithWidth pour que les elements non imprimables (cadres de redimmentionnement lors de la selection par exemple) sortent correctement a l'ecran (alignement sur des pixels, epaisseur en multiple de pixels etc...) ?

    De plus, avec le model actuel, j'ai trop de "blanc" autour de mon texte. Les valeurs numériques sont trop eloignees les unes des autres. je perds de la place. Ce type de schema ne doit pas prendre une surface démesurée sur une page de texte. (je n'imprimerai pas les bordures. peut-etre un fond tres light derriere les cellules...)

    Je ne veux pas non plus me retrouver a subclasser comme un fou. Ce n'est jamais une bonne idee.

    En dernier recours, je peux me baser sur NSForm pour voir un peu le genre de methodes a implementer pour rester dans l'esprit de cocoa et avoir un objet compatible avec le framework.
  • ShomeiShomei Membre
    16:51 modifié #9
    Je crois que je vais opter pour :

    Une classe derivée de NScontrol avec des NSTextFieldCells. Mais la doc est mince. Je n'ai pas trouvé de fonction similaires a addSubview pour intégrer la cellule nouvellement cree. et je ne sais pas trop comment effectivement gérer les cells.

    J'ai compris qu'il fallait que je les appelle pour qu'ils se dessinent a l'ecran, que le textfield editor de la fenetre allait se charger de gérer l'edition pour les differentes NSTextFieldCell. Mais concretement... je ne sais pas trop comment m'y prendre pour l'implémentation de l'objet lui meme.

    As-ton acces aux sources des classes de cocoa ? Comme aux MFC de windows ?
    J'ai essayé, mais le debug ne veux pas tracer dedans...
Connectez-vous ou Inscrivez-vous pour répondre.