Problème avec NSLog

Floppy

Membre expert
Club iGen
19 Avril 2001
1 621
40
Salut,

Je débute dans la programmation Cocoa avec le livre "Cocoa par la pratique" et j'ai vraiment un problème avec NSLog pour afficher un objet. Qui pourra me dire pourquoi ce bout de code ne fonctionne pas ?

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray * tableau = [[NSMutableArray alloc] init];
NSNumber * nbr;
int i;

for (i = 0; i < 10; i++)
{
[nbr = [NSNumber alloc] initWithInt:(3*i)];
NSLog(@"L'element %d vaut %@", i, nbr);
[tableau addObject:nbr];
[nbr release];
}

// NSLog(@"tableau = %@", tableau);

[tableau release];
[pool release];
return 0;
}

C'est pourtant pas compliqué mais il y a une erreur d'exécution dans la boucle sur NSLog :

2003-02-12 00:36:36.622 Loterie[9538] Did you forget to nest alloc and init?
2003-02-12 00:36:36.630 Loterie[9538] *** Uncaught exception: <NSInvalidArgumentException> *** -objCType only defined for abstract class. Define -[NSPlaceholderNumber objCType]!

Je vous jure que "nbr" n'est pas nul. D'après le débuggeur, l'execution tente d'appeler [NSNumber descriptionWithLocale:] qui appelle [NSPlaceholderNumber objCType] ce qui lève une exception.

Qu'est ce qui ne va pas ?

D'avance, merci pour votre aide.
 
<blockquote><font class="small">Post&eacute; &agrave; l'origine par Floppy:</font><hr />
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray * tableau = [[NSMutableArray alloc] init];
NSNumber * nbr;
int i;

for (i = 0; i &lt; 10; i++)
{
[nbr = [NSNumber alloc] initWithInt:(3*i)];
NSLog(@"L'element %d vaut %@", i, nbr);
[tableau addObject:nbr];
[nbr release];
}

// NSLog(@"tableau = %@", tableau);

[tableau release];
[pool release];
return 0;
}


[/QUOTE]

alors voici les quelques erreurs que j'ai repéré:

ton i est un int, pas un decimal, donc dans ton NSLog, remplace %d par %i

mais ce qui doit faire planter, c'est que
ta définition de nbr est fausse, tu places mal les crochets:
nbr= [[NSNumber alloc] initWithInt:(3*i)];

un petit conseil que tu comprendras avec le temps: plutôt que d'allouer comme ça et faire un release de nbr un peu plus tard, tu peux remplacer ça par:
nbr = [NSNumber numberWithInt:(3*i)];
ça te créé un objet autorelease tout de suite, et tu n'as donc plus besoin du release en fin de boucle.

le NSLog qui est maintenant en commentaire pourrait fonctionner si tu mettais:
NSLog(@"tableau = %@", [tableau description]);
ça marche sur beaucoup d'objets
 
<blockquote><font class="small">Post&eacute; &agrave; l'origine par grenoble:</font><hr /> alors voici les quelques erreurs que j'ai repérées :

ton i est un int, pas un decimal, donc dans ton NSLog, remplace %d par %i


[/QUOTE]
Je ne vois pas ce que tu entends par "décimal". Selon, la doc ( file:///Developer/Documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/DataFormatting/Tasks/FormatStrings.html ), %d et %i, c'est pareil. Par contre, ça fait référence à un entier 32 bits. Or, je pensais que les int faisaient 16 bits sur Mac. Je me trompe ?

<blockquote><font class="small">Post&eacute; &agrave; l'origine par grenoble:</font><hr /> mais ce qui doit faire planter, c'est que ta définition de nbr est fausse, tu places mal les crochets:
nbr= [[NSNumber alloc] initWithInt:(3*i)];


[/QUOTE]
En effet, c'est là qu'est le problème. J'avais d'abord écrit :
[nbr= [[NSNumber alloc] init] initWithInt:(3*i)];
Puis réalisant mon erreur, j'ai supprimé init mais je n'ai pas viré les bons crochets.
Maintenant que tu m'as donné la bonne syntaxe, ça marche bien. Merci.

<blockquote><font class="small">Post&eacute; &agrave; l'origine par grenoble:</font><hr /> un petit conseil que tu comprendras avec le temps: plutôt que d'allouer comme ça et faire un release de nbr un peu plus tard, tu peux remplacer ça par:
nbr = [NSNumber numberWithInt:(3*i)];
ça te créé un objet autorelease tout de suite, et tu n'as donc plus besoin du release en fin de boucle.


[/QUOTE]
Merci pour le tuyau.

<blockquote><font class="small">Post&eacute; &agrave; l'origine par grenoble:</font><hr /> NSLog qui est maintenant en commentaire pourrait fonctionner si tu mettais:
NSLog(@"tableau = %@", [tableau description]);
ça marche sur beaucoup d'objets.


[/QUOTE]
C'est ce que j'avais d'abord écrit mais ça ne marchait pas non plus à cause de la mauvaise initalisation des nbr. Mais maintenant, que c'est corrigé, ça marche tel quel.

Une petite question supplémentaire: Est-ce que tous les objets qu'on crée en Obj-C sont toujours des pointeurs ? Je ne sais pas pourquoi tableau est un pointeur. J'aurais plutôt crée une instance.

Merci pour ton aide.
 
&gt;Je ne vois pas ce que tu entends par "décimal". Selon, la doc (
&gt;file:///Developer/Documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/
&gt;DataFormatting/Tasks/FormatStrings.html ), %d et %i, c'est pareil. Par contre,
&gt;ça fait référence à un entier 32 bits. Or, je pensais que les int faisaient 16
&gt;bits sur Mac. Je me trompe ?

Mea culpa. je pensais que %d faisait référence à "double" ou decimal, alors que %i c'est plus naturel pour "integer", on s'embrouille vite avec toutes ces abbréviations, conventions, etc

(...)

&gt;Merci pour le tuyau.

ce principe marche pour tout: stringWithMachin dataWithTruc numberWithBidule etc... remplace les initWithMachin en créant des objets autorelease.

&gt;Une petite question supplémentaire: Est-ce que tous les objets qu'on crée en
&gt;Obj-C sont toujours des pointeurs ? Je ne sais pas pourquoi tableau est un
&gt;pointeur. J'aurais plutôt crée une instance.

Nuance: NSLog(@"tableau: %@", tableau) te donne l'adresse de l'objet tableau
et NSLog(@"tableau: %@, [tableau description]) te donne le contenu de l'objet tableau.

 
<blockquote><font class="small">Post&eacute; &agrave; l'origine par grenoble:</font><hr /> Nuance: NSLog(@"tableau: %@", tableau) te donne l'adresse de l'objet tableau
et NSLog(@"tableau: %@, [tableau description]) te donne le contenu de l'objet tableau.


[/QUOTE]

Hum... Les deux affichent le contenu du tableau mais je t'accorde que la seconde expression correpond davantage à ce que je recherche.

Cela dit, ce n'était pas le sens de ma question qui était plutôt: existe-il un opperateur "new" en obj-C ou est ce qu'on fait toujours:

id * objet;
[[objet alloc] init];

 
On fait toujours un alloc/init en objective C.
Ou alors, on peut cree un objet temporaire et l'affecter, mais il faut faire tres attention a faire un retain ensuite!!!
Le init fait un retain et met le compteur de reference a 1.

Donc tu peux faire :
NSDate *leChoixDansLaDate = [[NSDate alloc] init];

ou

NSDate *leChoixDansLaDate = [[NSDate date] retain];


Voilou.
 
Merci.

Encore une question:

Si j'oublis de désallouer quelques objets, sont-ils néanmoins détruits - et la mémoire libérée - lorsqu'on quitte le programme ? Ou la mémoire reste-elle définitivement encombrée par ces objets oubliés ?
 
Lorseque l'on quitte le programme, toute la memoire de ce processus est desallouee. Merci MacOS X! Cependant, dans ton programme, fais bien attention a ne pas avoir de fuite, ca peut etre tres embetant si c'est dans une boucle.


Pour decrementer le compteur d'une variable, utilise release :
[leChoixDansLaDate release];


Retain augmente le compteur de 1, release le decremente.
 
Merci d'avoir effacé ce doute. Je travaille couramment sur un OS qui désalloue tout lorsqu'on quitte le programme mais j'ai entendu dire que ce n'est pas le cas sous Windows
ooo.gif