listes chaînées en Objective-C

boulifb

Membre émérite
7 Septembre 2006
559
28
Bonjour tout le monde,

Après recherches, j'aimerais savoir s'il existe une classe qui va bien en Objective-C qui gère les liste simplement et/ou doublement chaînées.

J'ai été surpris de ne pas retrouver cette structure dans la section consacrée aux collections dans le CoreFoundation, à moins que ce soit dans une autre framework...

Cordialement.

Fred.
 

p4bl0

Membre d’élite
Club MacG
12 Juillet 2004
4 772
425
30
$PWD
p4bl0.net
Bonjour tout le monde,

Après recherches, j'aimerais savoir s'il existe une classe qui va bien en Objective-C qui gère les liste simplement et/ou doublement chaînées.

J'ai été surpris de ne pas retrouver cette structure dans la section consacrée aux collections dans le CoreFoundation, à moins que ce soit dans une autre framework...

Cordialement.

Fred.
C'est pas un truc du genre NSDictionary (je dis peut-être une connerie hein, je connais pas vraiment Cocoa ^^) la classe pour les liste ?

Après pour le truc de doublement chaînées (je sais pas du tout ce que c'est), ça doit pouvoir y être ajouter en sous classant NSDictionary si ce n'est pas déjà inclus.
 

jb_jb_fr

Membre junior
11 Septembre 2006
62
3
Marcoussis
Pourquoi s'embeter avec des listes chainées

Tu as la classe NSMutableArray qui te permet de gérer des tableaux d'objets.
Cette classe te permet:
- de connaitre le nombre d'objet
- de prendre l'objet d'index précédent
- de prendre l'objet d'index suivant
- de retirer n'importe quel objet dans la liste
- d'insérer un objet dans la liste à l'endroit que tu veux.
-...

Je pense qu'avec ça tu peux faire tout ce que tu veux.
Il y a même la possibilité de faire du tri ascendant/descendant

Jacques
 
  • J’aime
Réactions: p4bl0

Eul Mulot

Membre émérite
12 Juin 2006
821
73
32
Belfort
Comme l'a dit jb_jb_fr, c'est une des solutions très pratique pour faire une liste, de plus l'expension/réduction de la taille du tableau se fait dynamiquement, l'insertion d'un élément en index 5 va décaller les autres automatiquement et idem pour le retrait d'un objet.
 

boulifb

Membre émérite
7 Septembre 2006
559
28
@p4b10. Non!! NSDictionary ne répond pas à ma demande. Merci quand même ;)

@jb_jb_fr et eul mulot
Merci pour la solution concrète, je vais regarder la classe NSMutableArray. Le but du jeu est d'avoir une structure similaire à une liste chaînée (simplement ou doublement peu importe).

J'essaye désespérement de trouver la classe qui va bien pour lire un fichier et son contenu binaire, puis de charger certaines données dans une liste chaînée mais avec les classes Cocoa en Objective-C. Y a pas un équivalent de CFile quelque part en Objective-C???

C'est galère de ne pas connaître Cocoa :p
 

ntx

Vénérable sage
Club MacG
15 Octobre 2004
12 046
367
92
Pour ranger les données d'un fichier dans un arbre : les classes XML devrait faire l'affaire. Mais si ton fichier n'est pas en XML (et je suppose que c'est le cas :rateau: ) il va falloir te taper le parsing "à la main" mais ce n'est pas rédhibitoire.
 

Mala

Membre junior
9 Mai 2006
65
7
Comme ça vu de loin, j'aurais tendance à dire:
1) lire le fichier binaire avec une classe NSData.
2) sous réserve de connaître la structure binaire, récupérer les données via getBytes de NSData.
3) stocker les données dans un NSMutableArray qui rend obsolète l'utilisation d'une liste chaînée.
 

Mala

Membre junior
9 Mai 2006
65
7
Après pour le truc de doublement chaînées (je sais pas du tout ce que c'est)
Pour le côté culturel, une liste chaînée permet de parcourir une liste d'objet via des conteneurs (en générale une simple structure C) qui encapsule l'objet ainsi qu'un pointeur vers le conteneur suivant. On parle de double chaînage lorsqu'on dispose aussi d'un pointeur vers l'objet précédant Donc:

Chaînage simple -> je parcours ma liste du début vers la fin uniquement.
Chaînage double -> je parcours ma liste dans les deux sens.

Avec un NSArray/NSMutableArray, le problème ne se pose plus puisque pour parcourir la collection d'objets il suffit de passer en revue le tableau.
 
  • J’aime
Réactions: p4bl0

p4bl0

Membre d’élite
Club MacG
12 Juillet 2004
4 772
425
30
$PWD
p4bl0.net
Pour le côté culturel, une liste chaînée permet de parcourir une liste d'objet via des conteneurs (en générale une simple structure C) qui encapsule l'objet ainsi qu'un pointeur vers le conteneur suivant. On parle de double chaînage lorsqu'on dispose aussi d'un pointeur vers l'objet précédant Donc:

Chaînage simple -> je parcours ma liste du début vers la fin uniquement.
Chaînage double -> je parcours ma liste dans les deux sens.

Avec un NSArray/NSMutableArray, le problème ne se pose plus puisque pour parcourir la collection d'objets il suffit de passer en revue le tableau.
Merci :)
 

boulifb

Membre émérite
7 Septembre 2006
559
28
Merci pour les infos.
Je vais essayer ça ce midi.

Pour le contenu du fichier, il doit être lu binaire (fopen avec l'otion "rb"). Pour ce qui est de la signification de chacun des octets, pas de problème. Je sais ce qu'ils contiennent et comment les analyser. Je veux juste refaire la lecture du contenu du fichier en Objective-C avec les classes Cocoa. L'histoire de me familiariser avec le langage ;)

Dans cette optique, je m'amuse à refaire un jeu que j'avais écrit sous Windows en C ANSI via Allegro mais cette fois-ci en sous Mac OS X en Objective-C et Allegro (oui, ça tourne sur mac en natif via Cocoa et Quartz). Comme Allegro mixe C et Objective-C (pour la partie fenêtrage), normalement, je dois pouvoir aussi mixer les deux architectures dans mon jeu.

Fred.
 

boulifb

Membre émérite
7 Septembre 2006
559
28
Bon, j'ai essayé ne serait-ce que d'ouvrir le contenu d'un fichier en Cocoa et là, c'est la cata... J'ai bien parcouru la doc d'Apple (BinaryData.pdf et NSData_class.pdf) et fait comme dans l'exemple, mais rien n'y fait. J'ai dû louper un épisode...

Voici le programme:
Bloc de code:
#import <Foundation/Foundation.h>
 
#define SAFE_RELEASE(p)         { if (p) { [p release]; p=NULL; } }
 
int main(int argc, char** argv)
{
 NSString* fileName="Volumes/Data/Projects/objc/FF01"; // normalement il y a un @ apr&#232;s le =
 NSData*  fileContent=[NSData dataWithContentsOfFile: fileName];
 
 SAFE_RELEASE(fileContent);
 SAFE_RELEASE(fileName);
 return 0;
}
NB: Normalement, il y a un @ apr&#232;s le = et fileName est bien cr&#233;&#233;... Normalement, faut tester si fileName est bon avant d'appeler dataWithContentsOfFile, mais bon, l&#224;, c'est un exemple ;)

Voici la sortie:
Bloc de code:
2007-06-21 14:00:13.371 level[852] *** _NSAutoreleaseNoPool(): Object 0x304a30 of class NSCFString autoreleased with no pool in place - just leaking
2007-06-21 14:00:13.372 level[852] *** _NSAutoreleaseNoPool(): Object 0x3032a0 of class NSConcreteData autoreleased with no pool in place - just leaking
Si quelqu'un a une id&#233;e... C'est le bienvenue.

Cordialement.

Fred.
 

Mala

Membre junior
9 Mai 2006
65
7
Alors commen&#231;ons par le commencement. Objective-C et cocoa en g&#233;n&#233;ral fonctionne avec des "autorelease pool" qui permettent de s'affranchir dans certaines conditions de la gestion m&#233;moire. Chaque thread (dans ton cas ton main est le thread principal) doit disposer dau moins un pool qui va stocker et g&#233;rer les objets autorelease.

L&#224; tu vas me dire:"mais je fais tout moi m&#234;me".

Oui mais non, en appelant par exemple dataWithContentsOfFile tu utilises ce que l'on appel un constructeur de commodit&#233; qui te retourne un objet allou&#233; en mode autorelease (c'est comme &#231;a que fonctionne la plupart des constructeurs de commodit&#233;).

Du coup le programme pense qu'il y a une perte m&#233;moire car tu as cr&#233;&#233; un objet qui n'est associ&#233; &#224; aucun pool.

Donc pour r&#233;soudre ce probl&#232;me:
Ajoute en tout d&#233;but du main:
Bloc de code:
    NSAutoreleasePool *pool = [NSAutoreleasePool new];
Et &#224; la fin du code en toute derni&#232;re ligne:
Bloc de code:
    [pool release];
Et l&#224; &#231;a plante encore. Pourquoi?

Et bien tout simplement parce que ta macro SAFE_RELEASE n'a pas de raison d'&#234;tre sur des objets qui sont autorelease. Au contraire, tu vas lib&#233;rer les objets et derri&#232;re ton pool va essayer de faire de m&#234;me et patatra.

Deux solutions:
- Soit tu supprimes l'appel &#224; ta macro.
- Soit en tant que programmeur consciencieux tu ne l'entend pas de cette oreille et tu veux avoir tout pouvoir sur les objets que tu alloues dans ton code. Dans ce second cas, tu ajouteras le code suivant apr&#232;s la cr&#233;ation de tes objets:

Bloc de code:
    [fileName retain];
    [fileContent retain];
Et l&#224; pour faire simple, tu indiques &#224; l'autorelease pool qu'il est bien mignon mais que jusqu'&#224; preuve du contraire c'est toi le boss et que les objets tu te les lib&#232;res toi m&#234;me. :D

Toujours tr&#232;s perspicace, tu me r&#233;torques alors : "Quel est alors l'int&#233;r&#234;t des objets g&#233;r&#233;s en autorelease???"
Et bien imagines un objet dont l'utilisation est partag&#233;es par plusieurs autres objets (ex: une ressource genre une image jpeg). Lequel des objets &#224; le droit de supprimer l'espace m&#233;moire allou&#233; par l'objet image s'il n'en a plus besoin? Dur dilemme. :hein: Et l&#224; le mode autorelease prend tout son int&#233;r&#234;t. :zen: On passe l'objet image en tant qu'objet autorelease aux autres objets. Chaque objet qui veut conserver l'image fait alors un retain dessus et cela incr&#233;mente un compteur associ&#233; &#224; notre ressource. Une fois qu'un objet ne veux plus garder la ressource, il fait un release sur l'objet image. Lorsque le compteur arrive a z&#233;ro, plus personne n'utilise l'image alors l'objet se lib&#232;re.
 
  • J’aime
Réactions: Warflo et boulifb

boulifb

Membre émérite
7 Septembre 2006
559
28
Wizzzz &#231;a marche!

Dans mon cas, les ressources ne sont pas partag&#233;es. En effet, les fichiers que je vais &#234;tre amen&#233; &#224; manipuler sont sp&#233;cifiques au jeu.

Finalement, l'autorelease est &#224; Cocoa ce que le Garbage Collector est &#224; .NET si j'ai bien compris. On cr&#233;&#233; ses objets en m&#233;moire et lorsque la vie de l'objet est termin&#233; l'architecture se charge de n&#233;ttoyer le tout. Avec ces explications, &#231;a va d&#233;j&#224; mieux. :up:

J'ai donc bien loup&#233; un &#233;pisode dans les docs d'Apple. C'est que je voulais mettre les mains dans le camboui moi :p

Donc, en Objective-C via Cocoa, lorsque l'on utilise les constructeurs de commodit&#233; de classe, il vaut mieux utiliser la m&#233;thode retain plut&#244;t que release. En revanche, si on utilise la m&#233;thode init l&#224;, il faut bien utiliser la m&#233;thode release. C'est bien &#231;a?

NB: &#224; tout hasard, sous Xcode, comment on cr&#233;&#233; une application en ligne de commande en Objective-C? En gros, ce que j'ai fais avec vi, j'aimerais le refaire sous Xcode. Je pense que &#231;a doit &#234;tre faisable ;)
 

Mala

Membre junior
9 Mai 2006
65
7
Dans mon cas, les ressources ne sont pas partag&#233;es. En effet, les fichiers que je vais &#234;tre amen&#233; &#224; manipuler sont sp&#233;cifiques au jeu.
Et tu n'as pas des objets qui partagent des donn&#233;es communes dans ton jeux (ex: un jeu de dame o&#249; on pourrait imaginer avoir autant d'instances que de pions mais une seule image pour les pions blanc et une seule image pour les pions noir)? Enfin, bref c'&#233;tait pour te pr&#233;senter le principe.

Finalement, l'autorelease est &#224; Cocoa ce que le Garbage Collector est &#224; .NET si j'ai bien compris. On cr&#233;&#233; ses objets en m&#233;moire et lorsque la vie de l'objet est termin&#233; l'architecture se charge de n&#233;ttoyer le tout. Avec ces explications, &#231;a va d&#233;j&#224; mieux. :up:
En fait parler de Garbage Collector est un raccourci un peu rapide. En gros avec un GC, lorsque tu lib&#232;res un objet, la lib&#233;ration m&#233;moire se fera au bon vouloir du GC (d'o&#249; parfois des engorgements m&#233;moire si la machine est tr&#232;s sollicit&#233;e). Avec le principe d'objective-c, le fonctionnement est d&#233;terministe (on sait exactement &#224; quel moment les objets autorelease sont lib&#233;r&#233;s) contrairement aux langages qui utilisent un GC (Java,.Net,etc). On peut m&#234;me d'ailleurs utiliser des pool interm&#233;diaires dans des boucles faisant de gros traitements.
Exemple:

Bloc de code:
NSAutoreleasePool *poolPrincipal = [NSAutoreleasePool new];

// 
// Ici on peut faire plein de manip avec des objet autorelease
//
NSString *maSuperString = [NSString stringWithString:@"Etpataietpatata"];


// maintenant on passe &#224; la boucle
int patati = 0;
int patata = 10;
for(; patati<patata; patati++)
{
    NSAutoreleasePool *poolSecondaire = [NSAutoreleasePool new];

    //A partir de maintenant tous les objets autorelease sont g&#233;r&#233;s par le
    //pool secondaire

    // Ici on fait de gros traitements et comme on sait pas ce que font les 
    // classes cocoa qu'on j'utilise, il y a sans doute des objets autorelease 
    // qui font grimper la m&#233;moire

    // Enfin, on lib&#232;re le pool pour d&#233;gager tous les objets autorelease qui sont
    // obsol&#232;tes avant la boucle suivante.
    [poolSecondaire release];
}

// On lib&#232;re le pool principal qui va nettoyer les objets autorelease que l'on a
// &#233;ventuellement cr&#233;&#233; en dehors de la boucle. 
[poolPrincipal release];
Tout &#231;a pour bien montrer que contrairement au GC, on conserve ici la main mise sur la lib&#233;ration des objets (m&#234;me ceux autorelease). C'est donc plus fin qu'un GC et cela offre de meilleurs performances (pas de latence dans la lib&#233;ration m&#233;moire) car un GC n'aura jamais la qualit&#233; d'appr&#233;ciation d'un d&#233;veloppeur pour savoir exactement quand lib&#233;rer des donn&#233;es qui ne sont plus utiles.

Il est a noter cependant que la prochaine version d'OSX int&#233;grera un GC en compl&#233;ment de la gestion actuelle pour laisser le choix aux programmeurs. Donc pour ceux qui pr&#233;f&#232;rent ce sera dispo avec Obj-C 2.0.

J'ai donc bien loup&#233; un &#233;pisode dans les docs d'Apple. C'est que je voulais mettre les mains dans le camboui moi :p
Chaque langage a ses subtilit&#233;s qu'il est important d'int&#233;grer pour pouvoir se concentrer plus sereinement sur son code. Mais c'est vrai que c'est toujours tentant de partir &#224; l'aventure... ;)

Donc, en Objective-C via Cocoa, lorsque l'on utilise les constructeurs de commodit&#233; de classe, il vaut mieux utiliser la m&#233;thode retain plut&#244;t que release.
Je pense que tu as voulu dire autorelease au lieu de release? Il est effectivement pr&#233;f&#233;rable de toujours g&#233;rer soit m&#234;me les objets quand c'est possible. Maintenant, si tu as par exemple une m&#233;thode d'une classe qui doit retourner un objet et bien tu le mettras en autorelease pour des raisons de s&#233;curit&#233; (et par respect des conventions).

En revanche, si on utilise la m&#233;thode init l&#224;, il faut bien utiliser la m&#233;thode release. C'est bien &#231;a?
Oui tout ce qui est init... sont des constructeurs "simples" qui te retourne l'objet allou&#233; et c'est &#224; toi de d&#233;cider de le basculer ou pas en autorelease. C'est aussi le cas des m&#233;thodes de copies (copy et mutableCopy).
 

clampin

Membre d’élite
Club MacG
22 Septembre 2000
1 002
177
49
Louvain-La-Neuve, Belgique
www.clampin.com
Wizzzz ça marche!
NB: à tout hasard, sous Xcode, comment on créé une application en ligne de commande en Objective-C? En gros, ce que j'ai fais avec vi, j'aimerais le refaire sous Xcode. Je pense que ça doit être faisable ;)



C'est très simple tu va dans le menu File->New Project-> là tu choisis Command Line utility ->Foundation tool pour la faire en objective-C ou Standard Tool pour la faire en C.

Bonne découverte de cocoa...

Clampin
 

Mala

Membre junior
9 Mai 2006
65
7
obsol&#232;te concernant obj-c 2
Avant de sortir une phrase de son contexte, il est toujours int&#233;ressant de lire jusqu'au bout... ;)
Il est a noter cependant que la prochaine version d'OSX int&#233;grera un GC en compl&#233;ment de la gestion actuelle pour laisser le choix aux programmeurs. Donc pour ceux qui pr&#233;f&#232;rent ce sera dispo avec Obj-C 2.0.
Donc on y apprend :
1- qu'Obj-C 2.0 n'est pas encore disponible ce qui ne fait pas les affaires de notre ami aujourd'hui, maintenant, tout de suite.
2- qu'Obj-C m&#234;me en 2.0 continuera &#224; &#234;tre compatible avec une gestion autorelease/retain.
 

boulifb

Membre émérite
7 Septembre 2006
559
28
@clampin: ok, j'avais trouvé ;)

@mala
Par contre sous Xcode, via le débogueur, lorsque j'ouvre mon fichier, le nombre d'octets chargés est le bon (ouf), mais je n'arrive pas à voir en mémoire son contenu. Lorsque je déroule l'objet NSData, il y a un pointeur "isa" et puis c'est tout. Même si je demande à voir le contenu du pointeur, je n'ai pas les bonnes données visiblement. Je ne vois pas où sont stockés les octets lus.

Pour le moment, je commence à me familiariser à l'Objective-C. Pour la version 2, j'attendrais la sortie de Leopard et de Xcode 3... Un jour à la fois. J'ai jusqu'au mois d'Octobre pour me faire les dents. ;)

Sinon, venant du C/C++/C#, l'Objective-C n'est pas si méchant une fois le nez dedans.

Fred.