Gestion de la mémoire, implémentation de constructeurs et mixer ses sources ...

MulotMulot Membre
juin 2007 modifié dans API AppKit #1
Bon voici un post conséquent, qui contient beaucoup de petites questions de débutant. J'ai essayé de chercher des solutions mais en vain, alors j'aimerai bien un petit coup de main !

Jusqu'à  hier, j'avais commencé mon projet en essayant de le définir sur des bases saines, et en implémentant les classes nécessaires pour une première version alpha.

Pas de soucis lors de mes divers tests dans le main de mon Fundation Tool, pas de soucis d'allocation de mémoire et autre, tout marchait impeccablement bien.

Hier je me suis lancé dans quelques petits test avec Interface Builder et là  de suite ça a été moins drôle ! Nouveau dans l'utilisation de IB, ça m'a quelque peu dérouté et ce sur plusieurs points :

- le fait de devoir penser "à  tout" avant de commencer l'implémentation : en effet il faut à  chaque modification des outlets ou actions régénérer les classes dans Xcode, ce qui m'amène à  un autre petit soucis.

- la possibilité de mixer deux fichiers, dans l'idée c'est absolument génial, après dans la pratique je trouve ça plutôt mal foutu, ou alors je ne n'ai vraiment pas saisit le fonctionnement du truc. Par exemple quand je fait "merge", j'ai mes deux versions qui s'affichent (à  gauche une dans temp et à  droite la version dans mon répertoire du projet); dès le départ, les flèches vont de droite à  gauche, pourquoi inclure "d'anciens" bouts de code dans le temp qui ne sera plus là  après l'opération ?

Même en essayant de me débattre avec l'outil je n'arrive pas à  obtenir plein satisfaction de celui-ci, par exemple ma directive #import dans la déclaration de ma classe disparaà®t ainsi que le contenu des méthodes qui sont restée communes entre les deux version. J'essayerai quand même de revoir ce système car je dois vraiment mal m'y prendre !

- la façon pour IB de positionner et créer les outlets et assez déroutante mais très pratique après quelques utilisations. Par contre il me reste encore quelque petites questions qui vont vous paraà®tre ridicules (IB et Cocoa c'est tout nouveau pour moi), mais que j'aimerai vos poser.

Tout d'abord une question relative à  IB lui même; je voulais qu'un appui sur un NSButton me créer un objet dans les attributs étaient dans des TextField ou un NSDatePicker, et qu'une fois l'objet créé, un NSPanel (enfin tout du moins un panneau "neutralisant" la fenêtre principale ) apparaissent avec un seul choix de bouton "ok" pour confirmer, et que ce dernier disparaisse une cliquant dessus. Je n'ai pas réussi, en tentant diverses approches: une premier fois j'ai créé un Panel dans ma méthode que le bouton déclenchait, et j'ai essayé de l'afficher en tentant un display, rien ne se passait.

Ensuite j'ai créé ce panel dans IB, et je l'ai ajouté comme outlet à  mon (unique) controller, qui devait le rendre visible au moment voulu, bilan rien ne se passe. J'ai donc tenté une dernière chose, j'ai coché le fait de le rendre visible dès le démarrage de l'application, là  il apparaà®t bien mais impossible de le faire disparaà®tre avec une méthode.

Une autre façon à  laquelle j'avais pensé, était de mettre ma fenêtre principale en tant qu'Outlet de mon controller (pour en modifier le titre, et tenter de faire apparaà®tre une fenêtre "enfant" avec la référence de la fenêtre mère, mais aucun résultat.

J'ai donc abandonné cette idée pour l'instant. Ce qui m'amène à  d'autres soucis.


Ces problèmes touchent plus particulièrement à  mes classes que j'ai faite, et que je vous utiliser dans une GUI, étant donné que le modèle que je souhaite utiliser serait un MVC, en théorie pas besoin de toucher au code source, mais en fait je pense que des changements s'imposent.

Je vous expose rapidement ma structure, et surtout n'hésitez pas à  me faire part de vos remarques !

J'ai une classe AccountOwner, qui représente un client d'une banque:

#import &lt;Cocoa/Cocoa.h&gt;<br />@class Account;<br /><br />@interface AccountOwner : NSObject {<br /><br />@private<br />	//First and last name of the owner, adress<br />	NSString *lastname,*firstname,*adress;<br /><br />	//Owner birthday<br />	NSDate *birthday;<br />&nbsp; &nbsp; <br />	//Owner list of account<br />&nbsp; &nbsp; NSMutableArray * accountTab;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; int numberOfAccount ;<br />}<br /><br /><br />- (id) initWithFirstName: (NSString*) pfirstname andLastName: (NSString*) plastname andBirthDay: (NSDate*) date ;<br /><br />- (void) addAccount: (Account*) anAccount ;<br /><br />- (Account*) accountAtIndex: (int) index ;<br /><br />- (void) removeAccountAtIndex: (int) index ;<br /><br />- (void) setFirstName: (NSString*) name ;<br /><br />- (void) setLastName: (NSString*) lname ;<br /><br />- (void) setBirthDay: (NSDate*) bd ;<br /><br />- (void) setAdress: (NSString*) ad ;<br /><br />- (NSString*) getFirstName ;<br /><br />- (NSString*) getLastName ;<br /><br />- (NSString*) getAdress ;<br /><br />- (NSDate*) getBirthDay ;<br /><br />- (NSString*) description ;<br /><br />@end<br />


Et voici son implémentation, qui me cause quelques soucis:

//<br />//&nbsp; AccountOwner.m<br />//&nbsp; MoneyOrganizer_0.1<br />//<br />//&nbsp; Created by Mulot on 15/06/07.<br />//&nbsp; Copyright 2007 __MyCompanyName__. All rights reserved.<br />//<br /><br />#import &quot;AccountOwner.h&quot;<br /><br /><br />@implementation AccountOwner<br /> <br /><br />- (id) initWithFirstName: (NSString*) pfirstname andLastName: (NSString*) plastname andBirthDay: (NSDate*) date{<br />	<br />	id ret = nil;<br />	<br />	if(self = [super init]) {<br />	<br />		firstname = [NSString stringWithString: pfirstname];<br />&nbsp; &nbsp; &nbsp; &nbsp; lastname = [NSString stringWithString: plastname];<br />		birthday = date;<br />&nbsp; &nbsp; &nbsp; &nbsp; adress = @&quot;Unknown&quot;;<br />&nbsp; &nbsp; &nbsp; &nbsp; numberOfAccount = 0;<br />&nbsp; &nbsp; &nbsp; &nbsp; accountTab = [[NSMutableArray alloc] init];<br />		ret = self;<br />	}<br />	<br />	return ret;<br />	<br />}	<br /><br />- (void) addAccount: (Account*) anAccount {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; [accountTab insertObject: anAccount atIndex: numberOfAccount];<br />&nbsp; &nbsp; numberOfAccount++;<br />&nbsp; &nbsp; <br />}<br /><br />- (Account*) accountAtIndex: (int) index {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; id account = nil;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; if(index &gt;= 0 &amp;&amp; index &lt; [accountTab count]){<br />&nbsp; &nbsp; &nbsp; &nbsp;account =[accountTab objectAtIndex: index];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; return account;<br />}<br /><br />- (void) removeAccountAtIndex: (int) index {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; if(index&gt;= 0 &amp;&amp; index &lt; [accountTab count]){<br />&nbsp; &nbsp; &nbsp; &nbsp; [accountTab removeObjectAtIndex: index];<br />&nbsp; &nbsp; }<br />}<br /><br />- (void) setFirstName: (NSString*) name {<br />	<br />	firstname = [NSString stringWithString:name];<br />}	<br /><br />- (void) setLastName: (NSString*) lname {<br /><br />	lastname = [NSString stringWithString: lname];<br />}<br /><br />- (void) setBirthDay: (NSDate*) bd {<br />	<br />	birthday = bd;<br />}<br /><br />- (void) setAdress: (NSString*) ad {<br /><br />	adress = [NSString stringWithString:ad];<br />}<br /><br />- (NSString*) getFirstName {<br /><br />	return firstname;<br />}<br /><br />- (NSString*) getLastName {<br /><br />	return lastname;<br />}<br /><br />- (NSString*) getAdress {<br /><br />	return adress;<br />}<br /><br />- (NSDate*) getBirthDay {<br />	<br />	return birthday;<br />}<br /><br />- (NSString*) description {<br /><br />NSString * deb = [NSString stringWithFormat:@&quot;Account Owner &#092;nFirstname : %@&#092;nLastName :%@&#092;nAdress :%@&#092;nBirthday : %@&quot;,firstname,lastname,adress ,[birthday description]];<br /><br />&nbsp; &nbsp; NSEnumerator * enumerator = [accountTab objectEnumerator];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; id account;<br />&nbsp; &nbsp; NSMutableString * descaccount = [NSMutableString stringWithString:@&quot;&#092;n &quot;];<br />&nbsp; &nbsp; while( account = [enumerator nextObject]){<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; descaccount = [descaccount stringByAppendingString:[account description]];<br />&nbsp; &nbsp; &nbsp; &nbsp; descaccount = [descaccount stringByAppendingString:@&quot;&#092;n&quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; } <br />&nbsp; &nbsp; deb = [deb stringByAppendingString: descaccount];<br /><br />&nbsp; &nbsp; return deb;<br /><br />}<br /><br /><br />@end<br />


Donc j'ai aussi une classe Account et une classe Operation, très similaire à  celle-ci.

#import &lt;Cocoa/Cocoa.h&gt;<br />#import &lt;Foundation/Foundation.h&gt;<br />#import &quot;Operation.h&quot;<br /><br />@class AccountOwner;<br /><br /><br />@interface Account : NSObject {<br /><br />@private<br /><br />	//The operation arary<br />	NSMutableArray * operationtab;<br />	<br />	//The number of current operation in the array<br />	int numofoperation;<br />	<br />	//The name of the account<br />	NSString *accountname;<br />	<br />	AccountOwner * owner;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; BOOL accountOwned;<br />	<br />	//The account bank&#39;s name<br />	NSString *bankname;<br />	<br />	//The current sum of the account<br />	double currentaccountsum;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; //The amount to be add or sub for valueDates<br />&nbsp; &nbsp; double amountToBeAdded ;<br />	<br />	<br />	<br />}<br /><br />+ (BOOL) addWaitingOperation:(Operation*) operation ;<br /><br />- (double) amountToBeAdded ;<br /><br />- (id) initWithBankName: (NSString*) bname andAccountOwner: (AccountOwner*) owner andAccountName: (NSString*) account_name;<br /><br />- (void) addOperation: (Operation*) op ;<br /><br />- (BOOL) isOwned ;<br /><br />- (void) setOwned: (BOOL) boolean ;<br /><br />- (AccountOwner*) accountOwner ;<br /><br />- (void) setAccountOwner: (AccountOwner*) ao ;<br />&nbsp; &nbsp; <br />- (void) deleteOperationAtIndex: (int) ind ;<br /><br />- (Operation*) getOperationAtIndex: (int) ind ;<br /><br />- (void) sortByOperationDateAsc ;<br /><br />- (void) sortByOperationDateDesc ;<br /><br />- (void) sortByOperationValueAsc ;<br /><br />- (void) sortByOperationValueDesc ;<br /><br />- (void) sortByOperationNameAsc ;<br /><br />- (void) sortByOperationNameDesc ;<br /><br />- (void) sortByExpense ;<br /><br />- (void) sortByRevenue ;<br /><br />- (NSString*) description ;<br /><br />- (int) getNumberOfOperation ;<br /><br />- (int) getRetainCountAtIndex: (int) ind ;<br /><br />- (double) getCurrentAccountSum ;<br /><br /><br /><br />@end<br />


et l'implémentation que voici:

//<br />//&nbsp; Account.m<br />//&nbsp; MoneyOrganizer_0.1<br />//<br />//&nbsp; Created by Mulot on 15/06/07.<br />//&nbsp; Copyright 2007 __MyCompanyName__. All rights reserved.<br />//<br /><br />#import &quot;Account.h&quot;<br /><br />int intSortExpense(id num1, id num2, void *context)<br />{<br />&nbsp; &nbsp; BOOL v1 = [num1 getExpense];<br />&nbsp; &nbsp; BOOL v2 = [num2 getExpense];<br />&nbsp; &nbsp; if (v1 == TRUE &amp;&amp; v2 == FALSE)<br />&nbsp; &nbsp; &nbsp; &nbsp; return NSOrderedAscending;<br />&nbsp; &nbsp; else if (v2 == TRUE &amp;&amp; v1 == FALSE)<br />&nbsp; &nbsp; &nbsp; &nbsp; return NSOrderedDescending;<br />&nbsp; &nbsp; else<br />&nbsp; &nbsp; &nbsp; &nbsp; return NSOrderedSame;<br />}<br /><br />int intSortRevenue(id num1, id num2, void *context)<br />{<br />&nbsp; &nbsp; BOOL v1 = [num1 getRevenue];<br />&nbsp; &nbsp; BOOL v2 = [num2 getRevenue];<br />&nbsp; &nbsp; if (v1 == TRUE &amp;&amp; v2 == FALSE)<br />&nbsp; &nbsp; &nbsp; &nbsp; return NSOrderedAscending;<br />&nbsp; &nbsp; else if (v2 == TRUE &amp;&amp; v1 == FALSE)<br />&nbsp; &nbsp; &nbsp; &nbsp; return NSOrderedDescending;<br />&nbsp; &nbsp; else<br />&nbsp; &nbsp; &nbsp; &nbsp; return NSOrderedSame;<br />}<br /><br />@implementation Account<br /><br /><br />- (id) initWithBankName: (NSString*) bname andAccountOwner: (AccountOwner*) own andAccountName:(NSString*) paccountname {<br /><br />if(self = [super init]){<br />	<br />	operationtab = [[NSMutableArray alloc] init];<br />	numofoperation = 0;<br />	accountname = paccountname;<br />	owner = own;<br />	bankname = bname;<br />	currentaccountsum = 0.0;<br />&nbsp; &nbsp; amountToBeAdded = 0.0;<br />&nbsp; &nbsp; accountOwned = YES;<br />	return self;<br />	}<br />	<br />return nil;<br />}<br /><br />+ (BOOL) addWaitingOperation:(Operation*) operation {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; BOOL result = NO;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSDate * actualDate = [NSDate date];<br />&nbsp; &nbsp; NSDate * operationDate = [operation operationValueDate];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; if(actualDate == [operationDate laterDate: actualDate]){<br />&nbsp; &nbsp; &nbsp; &nbsp; result = YES;<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; return result;<br />}<br /><br />- (void) addOperation: (Operation*) op {&nbsp; &nbsp; <br /><br />	[operationtab insertObject: op atIndex : numofoperation];<br />	numofoperation++;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; //if the operation is up to be added<br />&nbsp; &nbsp; if([Account addWaitingOperation:op]){<br />&nbsp; &nbsp; &nbsp; &nbsp; if([op getExpense]){ <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentaccountsum -= [op getAmount];<br />&nbsp; &nbsp; &nbsp; &nbsp; }else{<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentaccountsum += [op getAmount];<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; }else{<br />&nbsp; &nbsp; &nbsp; &nbsp; if([op getExpense]){ <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; amountToBeAdded -= [op getAmount];<br />&nbsp; &nbsp; &nbsp; &nbsp; }else{<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; amountToBeAdded += [op getAmount];<br />&nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; }&nbsp; &nbsp; <br />&nbsp; &nbsp; [op autorelease];<br />&nbsp; &nbsp; //Use a selector in order to sort account with the user choosen sorting type<br />&nbsp; &nbsp; [self sortByOperationDateAsc];<br />&nbsp; &nbsp; <br />}<br /><br />- (double) amountToBeAdded {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; return amountToBeAdded;<br />}<br /><br />- (void) deleteOperationAtIndex: (int) ind {&nbsp; &nbsp; <br />	<br />	<br />&nbsp; &nbsp;	if(numofoperation &gt;= 0 &amp;&amp; ind &lt; [operationtab count]){<br />		numofoperation--;<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; Operation * operationToDelete = [operationtab objectAtIndex:ind];<br />&nbsp; &nbsp; &nbsp; &nbsp; BOOL expense = [operationToDelete getExpense];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; if([Account addWaitingOperation: operationToDelete]){<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(expense){<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentaccountsum += [operationToDelete getAmount];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }else{<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentaccountsum -= [operationToDelete getAmount];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; }else{<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(expense){<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; amountToBeAdded += [operationToDelete getAmount];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }else{<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; amountToBeAdded -= [operationToDelete getAmount];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />		[operationtab removeObjectAtIndex:ind];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />	}<br />}<br /><br />- (AccountOwner*) accountOwner {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; return owner;<br />}<br /><br />- (void) setAccountOwner: (AccountOwner*) ao {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; owner = ao;<br />}<br /><br />- (BOOL) isOwned {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; return accountOwned;&nbsp; &nbsp;<br />}<br /><br />- (void) setOwned: (BOOL) boolean {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; accountOwned = boolean;<br />}<br /><br />- (Operation*) getOperationAtIndex: (int) ind {&nbsp; <br />		<br />	return [operationtab objectAtIndex:ind];<br />}<br /><br />- (void) sortByOperationValueAsc {&nbsp; &nbsp; &nbsp; &nbsp;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@&quot;op_amount&quot;ascending:YES] autorelease];<br />&nbsp; &nbsp; NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br />}<br /><br />- (void) sortByOperationValueDesc {&nbsp; &nbsp; &nbsp; &nbsp;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@&quot;op_amount&quot;ascending:NO] autorelease];<br />&nbsp; &nbsp; NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br />}<br /><br />- (void) sortByOperationDateAsc {&nbsp; &nbsp;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@&quot;op_date&quot;ascending:YES] autorelease];<br />&nbsp; &nbsp; NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br />}<br /><br />- (void) sortByOperationDateDesc {&nbsp; &nbsp;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@&quot;op_date&quot;ascending:NO] autorelease];<br />&nbsp; &nbsp; NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br />}<br /><br />- (void) sortByOperationNameAsc {&nbsp; &nbsp;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@&quot;op_designation&quot;ascending:YES] autorelease];<br />&nbsp; &nbsp; NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br />&nbsp; &nbsp; <br />}<br /><br />- (void) sortByOperationNameDesc {&nbsp; &nbsp;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@&quot;op_designation&quot;ascending:NO] autorelease];<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />&nbsp; &nbsp; NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br />&nbsp; &nbsp; <br />}<br /><br />- (void) sortByExpense {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; operationtab = [operationtab sortedArrayUsingFunction:intSortExpense context:NULL];<br /><br />}<br /><br />- (void) sortByRevenue{<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; operationtab = [operationtab sortedArrayUsingFunction:intSortRevenue context:NULL];<br /><br />}<br /><br />- (int) getRetainCountAtIndex: (int) ind {<br />	<br />	int nb;<br />	<br />	if( [operationtab count] &gt; ind ){<br />		nb = [[operationtab objectAtIndex:ind] retainCount];<br />	}else{<br />		nb = -1;<br />	}<br />	<br />	return nb;<br />}<br /><br /><br />- (NSString*) description {<br />	<br />	id operation;<br />	<br />	NSEnumerator * enumerator = [operationtab objectEnumerator];<br /><br />	NSMutableString * begining = [NSMutableString stringWithFormat:@&quot;Acount description : &#092;nBank: %@&#092;nName: %@ &#092;nAmount: %.2f &#092;nAmount waiting: %.2f&#092;n&#092;n&quot;,bankname,accountname,[self getCurrentAccountSum],amountToBeAdded];<br /><br />	while(operation = [enumerator nextObject]){<br />		begining = [begining stringByAppendingString:@&quot;&#092;n&quot;];<br />		begining = [begining stringByAppendingString:[operation description]];<br />	}<br />	return begining;<br />	<br />}<br /><br /><br />- (int) getNumberOfOperation {<br />	<br />	return numofoperation;<br />}<br /><br />- (double) getCurrentAccountSum {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; return currentaccountsum;<br />}<br />&nbsp; &nbsp; <br /><br /><br />@end<br /><br />


Pour la classe Opération c'est moins de problème, je l'exposerai au besoin.

Mon controller s'occupant de la création d'utilisateurs et d'opérations comporte tout les outlets nécessaires à  saisir les informations pour les attributs, ainsi qu'un outlet de type AccountOwner, qui est relié dans IB avec mon Controller.

En gros dans mon nib file j'ai ce qu'il y a au départ avec deux instances, une du Controller et une de AccountOwner, reliée à  l'outlet du Controller. J'ai aussi ajouté deux instances de type Account et Operation, qui ne sont elles reliées à  rien dans IB.

Mon accountOwner (outlet) dans mon controller est ici unique pour l'instant, possède un tableau de comptes (je lui créé un compte bidon automatiquement lors de sa création), et un tableau de compte comporte un tableau d'opérations. Je ne sais déjà  donc pas si ce modèle est bien choisit, étant donné que mon contrôleur possède un objet de type AccountOwner, et que celui-ci à  un tableau de compte, comportant eux même des opérations. Donc nécessaire ou pas de les instanciers (Account et Operations) dans le NIB File ?


Mes soucis sont donc : est-ce que mes méthodes init sont convenablement construites pour les objets, notamment par rapport aux allocations de mémoire et à  sa gestion.

Je m'explique : les valeurs de type String, ou Date, sont récupérées dans des textfield ou des DatePicker, puis dans la méthode action du bouton créer, j'utilise le constructeur de AccountOwner sur mon outlet accountOwner pour l'instancier.

Donc étant donné que en paramètre de init je place des méthodes de type [firstNameField stringValue], faut-il que dans mon init... je fasse  firstName = [[NSString alloc] initWithString: monparam]; ou puis-je faire un simple firstName = [NSString stringWithString:monparam]; ?

Qu'en est-il de l'objet passé en paramètre, il sera forcement plus valide quand je créerai un autre utilisateur. Idem pour les accesseurs et les setters, je sais que dans un poly de "Memory Management", il y a 3 façon de les faire, dont une qui m'est totalement obscure et consistant à  autoreleaser l'objet en le retournant ...

Une me parait "logique", l'accesseur retourne simplement la valeur, le setter autorelease l'ancienne valeur, et la valeur placée en paramètre lui est affectée avec un retain.

Comment puis-je être sur ques mes objets contiennent bien des objets qui leur sont propres et qui ne vont pas cherchers dans des méthodes extérieur ou dans des textFields, donc en fait, est-ce que je dois utiliser des alloc et copy à  la volée ?

Voilà , ça fait beaucoup de choses, mais étant donné que "Cocoa par la pratique" est en cours de route, j'en profite pour vous poser mes questions de débutant.

Merci par avance.
«1

Réponses

  • Philippe49Philippe49 Membre
    22:28 modifié #2
    dans 1182691688:

    - le fait de devoir penser "à  tout" avant de commencer l'implémentation : en effet il faut à  chaque modification des outlets ou actions régénérer les classes dans Xcode, ce qui m'amène à  un autre petit soucis.


    Personnellement, je fais les changements dans XCode, puis dans IB j'utilises l'option read MyClasse.h (ou ce qui est équivalent faire un glisser-déposer de XCode vers IB
  • Philippe49Philippe49 Membre
    22:28 modifié #3
    dans 1182691688:

    J'ai une classe AccountOwner, qui représente un client d'une banque:


    ...
    - (NSString*) getFirstName ;

    - (NSString*) getLastName ;

    - (NSString*) getAdress ;

    - (NSDate*) getBirthDay ;

    - (NSString*) description ;

    @end



    La tradition en objective-C serait plutôt les noms
    - (NSString*) firstName ;

    - (NSString*) lastName ;

    - (NSString*) adress ;

    - (NSDate*) birthDay ;

    pour les accessors methods
  • Philippe49Philippe49 Membre
    22:28 modifié #4
    dans 1182691688:


    Et voici son implémentation, qui me cause quelques soucis:

    - (id) initWithFirstName: (NSString*) pfirstname andLastName: (NSString*) plastname andBirthDay: (NSDate*) date{

    id ret = nil;

    if(self = [super init]) {

    firstname = [NSString stringWithString: pfirstname];
            lastname = [NSString stringWithString: plastname];
    birthday = date;
            adress = @Unknown;
            numberOfAccount = 0;
            accountTab = [[NSMutableArray alloc] init];
    ret = self;
    }

    return ret;

    }

    La variable ret ne sert à  rien. renvoyer self

    dans 1182691688:

    - (void) addAccount: (Account*) anAccount {
       
        [accountTab insertObject: anAccount atIndex: numberOfAccount];
        numberOfAccount++;
       
    }

    addObject n'est-elle pas une méthode suffisante ?

    dans 1182691688:

    - (void) setFirstName: (NSString*) name {

    firstname = [NSString stringWithString:name];
    }


    Ne marche pas car
    1) L'ancien firstName n'est pas détruit
    2) Le nouveau n'est pas retenu
    Voir Cocoa par la pratique sur ce sujet.
  • MulotMulot Membre
    juin 2007 modifié #5
    Oui je m'en suis rendu compte qu'après, d'ailleurs ce code est assez immonde en soit au niveau noms de variables et méthode et commentaires. je n'ai pas eu le courage de tout recommencer en fait, mais pour un projet projet je m'y tiendrai dès le début.

    Edith: pour le coup du ret, c'est que je n'aime pas avoir plusieurs return, alors quand je peux éviter, je fais ce genre de chose (qui à  dit maniaque ?!).

    Ensuite pour les setters, il faut donc bien autorelease l'ancien objet, et le remplacer par celui en param que l'on retain donc ?  Il en va de même pour les init ? il faut que je libère les objets en paramètres après les avoirs attribués à  mes attributs ?

    Par exemple:

    <br /><br />- initWithFirstName: (NSString*) firstName and BirthDay:(NSDate*) birthDay {<br /><br />if(self = [super init]){<br /><br />//est ce que ici on a bien userFirstName avec un retainCount de 1 et je peux ensuite détruire firstName<br />userFirstName = [[NSString alloc] initWithString:firstName];<br /><br />//J&#39;alloue de la mémoire pour ma date que où je mets une copie de celle en paramtre, ma date en attribut a un retainCount aussi de 1<br />userBirthDay = [[NSDate alloc] init];<br />userBirthDay = [birthDay copy];<br /><br />//Libération des paramètres<br />[birthDay autorelease];<br />[firstName autorelease];<br /><br />return self;<br /><br />}<br /><br />return nil;<br /><br />}<br />
    


    Mais si ici les attributs sont des string pris dans des texts fields, est-il nécessaire de les autoreleaser ?

    Peut-on aussi utiliser release au lieu de autorelease pour détruire les attributs du init, si on sait qu'ils ont un retainCount de 1 ?
  • schlumschlum Membre
    22:28 modifié #6
    Un "setter" en Objective-C se fait de cette manière (enfin c'est une des manières...) :

    - (void)setVar:(id)v<br />{<br />&nbsp; &nbsp; [v retain];<br />&nbsp; &nbsp; [var release];<br />&nbsp; &nbsp; var = v;<br />}
    


    Et dans cet ordre précis, car si on fait le "release" avant le "retain" et que v==var avant, tu imagines le résultat...  :P

    Effectivement, un "getter" ne prend pas "get" dans son nom par convention.
  • MulotMulot Membre
    22:28 modifié #7
    J'essaie de comprendre les allocations, retain et release, pour cela je me suis fait un classe Personne avec 4 attributs : deux String, une Date et un Tableau de personnes.

    Par contre j'ai encore un doute qui subsiste, au niveau de l'autorelease Pool :

    Voici ma petite classe :

    <br /><br />#import &quot;Personne.h&quot;<br /><br /><br />@implementation Personne<br /><br />- (id) initWithNom: (NSString*) n andPrenom: (NSString*) p andDateNaiss: (NSDate*) date {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; if(self = [super init]){&nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; nom = [[NSString alloc] initWithString:n];<br />&nbsp; &nbsp; &nbsp; &nbsp; prenom = [[NSString alloc] initWithString:p];<br />&nbsp; &nbsp; &nbsp; &nbsp; dateNaissance = [[NSDate alloc] init];<br />&nbsp; &nbsp; &nbsp; &nbsp; dateNaissance = [date copy];<br />&nbsp; &nbsp; &nbsp; &nbsp; amis = [[NSMutableArray alloc] init];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; [n release];<br />&nbsp; &nbsp; &nbsp; &nbsp; [p release];<br />&nbsp; &nbsp; &nbsp; &nbsp; [date release];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; return self;<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; return nil;<br />}<br />&nbsp; &nbsp; <br /><br />- (NSString*) nom {<br />&nbsp; &nbsp; return nom;<br />}<br /><br />- (NSString*) prenom {<br />&nbsp; &nbsp; return prenom;<br />}<br /><br />- (NSMutableArray*) amis {<br />&nbsp; &nbsp; return amis;<br />}<br /><br />- (NSDate*) dateNaissance {<br />&nbsp; &nbsp; return dateNaissance;<br />}<br /><br />- (void) setNom: (NSString*) newNom {<br />&nbsp; &nbsp; [newNom retain];<br />&nbsp; &nbsp; [nom release];<br />&nbsp; &nbsp; nom = newNom;<br />}<br /><br />- (void) setPrenom: (NSString*) newPrenom {<br />&nbsp; &nbsp; [newPrenom retain];<br />&nbsp; &nbsp; [prenom release];<br />&nbsp; &nbsp; prenom = newPrenom;&nbsp;  <br />}<br /><br />- (void) setDateNaiss: (NSDate*) newDate {<br />&nbsp; &nbsp; [newDate retain];<br />&nbsp; &nbsp; [dateNaissance release];<br />&nbsp; &nbsp; dateNaissance = newDate;<br />}<br /><br />- (NSString*) description {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSString * string = [NSString stringWithFormat:@&quot;Je suis %@ %@ , je suis ne le %@ et mes amis sont: &#092;n&quot;,prenom<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,nom<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ,[dateNaissance description]];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSEnumerator * en = [amis objectEnumerator];<br />&nbsp; &nbsp; id ami;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; while( ami = [en nextObject]){<br />&nbsp; &nbsp; &nbsp; string = [string stringByAppendingString:[ami prenom]];<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; return string;<br />}<br /><br />- (void) dealloc {<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; nom = nil;<br />&nbsp; &nbsp; prenom = nil;<br />&nbsp; &nbsp; dateNaissance = nil;<br />&nbsp; &nbsp; amis = nil;<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; [super dealloc];<br />}<br /><br />@end<br /><br />
    


    et mon main:

    <br />NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSString * pNom = [[NSString alloc] initWithString:@&quot;ZEVITCH&quot;];<br />&nbsp; &nbsp; NSString * pPrenom = @&quot;Mulot&quot;;<br />&nbsp; &nbsp; NSDate * pDateNaissance = [[NSDate alloc] initWithString:@&quot;1988-30-06 17:00:00 +00&quot;];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; Personne * moi = [[Personne alloc] initWithNom: pNom andPrenom: pPrenom andDateNaiss: pDateNaissance];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSLog([moi description]);<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSLog(pNom); // n&#39;affiche rien, normal car release dans le init.. sur une alloc<br />&nbsp; &nbsp; NSLog(pPrenom);//affiche Mulot car gere par la pool, liberee a la fin du main<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; //n&#39;affiche rien car realease dans le init... et fait crasher le programme<br />&nbsp; &nbsp; // car objet null&nbsp; &nbsp; <br />&nbsp; &nbsp; NSLog([pDateNaissance description]); <br />&nbsp; &nbsp; <br />&nbsp; &nbsp; NSLog([moi description]);<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; [pool release];<br />
    


    Ici, j'ai donc un Nom déclaré avec un alloc et init, que je dois soit mettre en autorelease pour qu'il soit libéré à  la fin de l'execution de la méthode, ou alors que je dois release pour qu'il soit de suite dealloc.

    Dans le premier cas, si je l'autorelease, c'est la pool qui s'en charge, mais par contre ,lorsque je change d'endroit le [pool autorelease], et que j'essaie d'afficher le contenu de ma variable cela fonctionne, est ce que ça vient du fait que l'autorelease se passe à  la fin de la méthode où se trouve la pool le contenant ?

    Le prénom est déclaré ici avec un simple init, ce qui à  pour conséquence de le placer dans la pool, je peux lui faire release ou autorelease et il ne sera libéré qu'a la fin de la méthode dans laquelle il a été créé non ?

    La date crééé en "dur" avec un alloc et init se voit release dans le constructeur, elle n'est donc plus existante une fois cette étape.

    En utilsant une méthode de description dans ma classe Personne, j'ai bien mes attributs affichés correctement, ce qui était mon but recherché.

    Question: Est-t-il "mieux" d'utiliser des objets que l'on a passé en paramètre pour les garder en tant que variable d'instance, ou plutôt de les "copier" ou d'en recréer des identiques et supprimer ceux en paramètres ? Cette question je me la pose pour ma version GUI, où tous les paramètres de mes constructeurs et/ou setters sont du type [textField stringValue] ou [datePicker dateValue].

    Est-ce que ma classe ci dessus est "propre" et "optimisée" (si on peut dire ça pour un truc aussi simple) ? Doive rajouter une AutoreleasePool pour la méthode description ? Est-ce que la méthode dealloc est faite correctement ?

    Merci de votre patiente, je suis assez long au démarrage et j'ai bien savoir exactement ce que je fais, et non pas modifier au pif et voir que ça marche et ne pas me poser de questions.
  • schlumschlum Membre
    22:28 modifié #8
    Hou là  là ...

    dateNaissance = [[NSDate alloc] init];<br />dateNaissance = [date copy];
    

    -> leak : tu alloues une date, puis tu remplaces le pointeur dessus par une copie d'un autre objet !

    dateNaissance = [date retain];
    


    Et par ailleurs, inutile de faire des copies de chaà®nes :
    nom = [n retain];<br />prenom = [p retain];
    


    [n release];<br />[p release];<br />[date release];
    

    C'est absolument pas à  ton constructeur de faire ça !
    Laisse la méthode qui a appelé le constructeur gérer sa mémoire comme elle l'entend.

    Les setters & getters c'est OK 

    Pour le "description", il vaudrait mieux travailler avec un NSMutableString, mais c'est OK aussi...

    Le dealloc n'est pas bon du tout !
    Il faut envoyer "release" à  tous les objets...
  • schlumschlum Membre
    22:28 modifié #9
    Pour le main, tu crées des objets dont tu ne libères pas la mémoire... "pNom", "pDateNaissance" et "moi"

    Je te conseille de compulser "Cocoa par la pratique"  ;)
  • MalaMala Membre, Modérateur
    22:28 modifié #10
    Peut-être un petit article sur le sujet pour prendre du recul sur la question?
    Gestion de la mémoire en Objective-C
  • schlumschlum Membre
    22:28 modifié #11
    dans 1182703837:
    Ici, j'ai donc un Nom déclaré avec un alloc et init, que je dois soit mettre en autorelease pour qu'il soit libéré à  la fin de l'execution de la méthode, ou alors que je dois release pour qu'il soit de suite dealloc.

    Pas besoin d'autorelease ; il y a les constructeurs de commodité pour ça...
    [NSString stringWithString:@ZEVITCH];

    Dans le premier cas, si je l'autorelease, c'est la pool qui s'en charge, mais par contre ,lorsque je change d'endroit le [pool autorelease], et que j'essaie d'afficher le contenu de ma variable cela fonctionne, est ce que ça vient du fait que l'autorelease se passe à  la fin de la méthode où se trouve la pool le contenant ?

    Rien compris...

    Le prénom est déclaré ici avec un simple init, ce qui à  pour conséquence de le placer dans la pool, je peux lui faire release ou autorelease et il ne sera libéré qu'a la fin de la méthode dans laquelle il a été créé non ?

    Il est statique ; il n'y a pas d'init.

    La date crééé en "dur" avec un alloc et init se voit release dans le constructeur, elle n'est donc plus existante une fois cette étape.

    Il ne faut surtout pas faire ça ; un constructeur n'a pas à  envoyer un release à  ses arguments !

    Question: Est-t-il "mieux" d'utiliser des objets que l'on a passé en paramètre pour les garder en tant que variable d'instance, ou plutôt de les "copier" ou d'en recréer des identiques et supprimer ceux en paramètres ? Cette question je me la pose pour ma version GUI, où tous les paramètres de mes constructeurs et/ou setters sont du type [textField stringValue] ou [datePicker dateValue].

    Si c'est objets sont non mutable, il faut sans conteste se contenter de faire un retain dessus.
    Pour un mutable, envisager la copie...

    Est-ce que ma classe ci dessus est "propre" et "optimisée" (si on peut dire ça pour un truc aussi simple) ? Doive rajouter une AutoreleasePool pour la méthode description ? Est-ce que la méthode dealloc est faite correctement ?

    Non, pas besoin d'AutoReleasePool dans la description. Pour le reste, cf. au-dessus...
  • MulotMulot Membre
    22:28 modifié #12
    Merci à  vous pour les infos, en fait au départ je me posais moins de question et j'avais moins de soucis !
    En fait ça commence à  devenir clair, et je ne sais pas pourquoi je voulais supprimer les paramètres pour les dupliquer ensuite en tant que paramètre.

    Par exemple, concrètement, j'ai une Operation, qui à  disons 2 attributs, un NSDate, et l'autre NSString. Ces valeurs je les récupère avec un textfield, et la date avec un datePicker. Donc par exemple dans une méthode appelée suite à  un clic sur un boutton, il y a

    <br />// le textField et le datePicker sont des outlets de la classe <br />// newOperation est un attribut d&#39;instance<br />newOperation = [[Operation alloc] initWithDesignation: [desField stringValue] andDate: [datePicker dateValue]];<br />
    


    Donc dans mon constructeur version "normale", je fais juste:

    <br /> - (id) initWithDesignation:(NSString*) des andDate:(NSDate*) date {<br /><br />if(self = [super init]{<br /><br />//retourne un nouveau pointeur, ne depend plus de des<br />designation = [NSString stringWithString:des] ;<br /><br />//on garde le param sous le coude, retourne un pointeur vers cet objet<br />operationDate = [date retain];<br /><br />return self;<br />}<br />return nil;<br />}<br /><br />
    



    Mais ça ne m'empèche pas de me poser cette question, concrètement, que devien la date en retain qui était générée par un datevalue sur un datePicker, j'ai un peu de mal là  ...
  • Philippe49Philippe49 Membre
    22:28 modifié #13
    dans 1182710896:

    - (id) initWithDesignation:(NSString*) des andDate:(NSDate*) date {

    if(self = [super init]{

    //retourne un nouveau pointeur, ne depend plus de des
    designation = [NSString stringWithString:des] ;

    //on garde le param sous le coude, retourne un pointeur vers cet objet
    operationDate = [date retain];

    return self;
    }
    return nil;
    }


    - (id) initWithDesignation:(NSString*) des andDate:(NSDate*) date {

    if(self = [super init]{

          //retourne un nouveau pointeur, ne depend plus de des
          designation = NSString stringWithString:des] [b]retain[/b;

        //on garde le param sous le coude, retourne un pointeur vers cet objet
        operationDate = [date retain];
    }
    return self;
    }

  • schlumschlum Membre
    22:28 modifié #14
    "des" n'était pas mutable, pourquoi tiens-tu absolument à  le copier ?  ???

    designation = [des retain];
    


    Tout simplement...
  • juin 2007 modifié #15
    Et en admettant qu'il soit mutable, pourquoi ne pas passer par une méthode qui est faite pour ça:

    [tt]designation = [des copy];[/tt]

    plutot que de passer par un objet autoreleasé?

    Et si c'est immutable, eh bien, copy se contente de faire un retain, donc pourquoi s'ennuyer à  savoir si c'est immutable ou mutable.

    PS: très bon choix Mala.
  • MalaMala Membre, Modérateur
    22:28 modifié #16
    :)
  • schlumschlum Membre
    juin 2007 modifié #17
    Pour éviter de passer par un appel superflu  :P
    (qui en plus va faire des tests sur la mutabilité etc...)
  • Philippe49Philippe49 Membre
    juin 2007 modifié #18
    Un petit essai pour éclairer les propos précédenrs :


    /* compiler avec :  % gcc pgm.m -o pgm -framework Foundation */

    #import <Foundation/Foundation.h>

    int main(int argc, char * argv[] ){
    NSAutoreleasePool * pool=[NSAutoreleasePool new];
    NSString * str1=[[NSString alloc] initWithString:@machin];
    NSMutableString * str2=[[NSMutableString alloc] initWithString:@machin] ;
    NSString * str3=[str1 copy] ;
    NSString * str4=[str2 copy] ;    // ou NSMutableString
    printf("Adresse de la chaà®ne str1 : %p retenue %d fois\n",str1,[str1 retainCount]);
    printf("Adresse de la chaà®ne str2 : %p retenue %d fois\n",str2,[str2 retainCount]);
    printf("Adresse de la chaà®ne str3 : %p retenue %d fois\n",str3,[str3 retainCount]);
    printf("Adresse de la chaà®ne str4 : %p retenue %d fois\n",str4,[str4 retainCount]);
    [str1 release];
    [str2 release];
    [str3 release];
        [str4 release];
    [pool release];
    }


    Résultat : str2!=str4 , str1=str3

    Adresse de la chaà®ne str1 : 0x304720 retenue 2 fois
    Adresse de la chaà®ne str2 : 0x304890 retenue 1 fois
    Adresse de la chaà®ne str3 : 0x304720 retenue 2 fois
    Adresse de la chaà®ne str4 : 0x304900 retenue 1 fois

  • veveveve Membre
    juin 2007 modifié #19
    Comprend pas la, pourquoi les NSString sont retenue 2 fois ? et les NSMutableString 1 fois ?

    Pour moi elle devrai être retenu le meme nombre de fois (NSString et NSMutableString) et 1 seul fois dans ce cas !!!!
  • schlumschlum Membre
    22:28 modifié #20
    dans 1182783295:

    Comprend pas la, pourquoi les NSString sont retenue 2 fois ? et les NSMutableString 1 fois ?

    Pour moi elle devrai être retenu le meme nombre de fois (NSString et NSMutableString) et 1 seul fois dans ce cas !!!!


    Regarde les adresses... str1 == str3  ;)
  • MulotMulot Membre
    22:28 modifié #21
    Merci pour ces réponses, après une bonne nuit de sommeil et de boulot, j'y vois plus clair. Faut dire que je me mange pas mal d'Objective-C / Cocoa niveau poly , donc un peu de mal à  assimiler, je vais baisser la cadence.

    Donc en fait utiliser copy est assez dangereux dans la mesure que si on copie un objet immutable, on retourne un pointeur sur le même objet, alors que si on essaye de copier un objet mutable cela retourne un pointeur vers une nouvelle zone mémoire, contenant l'objet identique. Donc dans ce cas on peut release l'objet mutable que l'on a copié et la copie n'en pâtira donc pas ?

    En tout cas je vais réécrire mes classes au propre et calmement avec ces informations que vous m'avez apporté !

  • schlumschlum Membre
    22:28 modifié #22
    Non, pas dangereux dans la mesure où ça incrémente le compteur de références de l'objet non mutable...
  • Philippe49Philippe49 Membre
    juin 2007 modifié #23
    dans 1182794091:

    Non, pas dangereux dans la mesure où ça incrémente le compteur de références de l'objet non mutable...


    ben oui, si trois personnes ont besoin du même objet, chacune des trois personnes prend un jeton sur cet objet (via retain), et ce n'est que quand les 3 jetons sont rendus (via release) que l'objet disparaà®t .
    copy fait un retain sur l'objet copié si il est immutable (on dit variable constante en C)  et il n'y a à  priori pas de danger particulier.
  • AliGatorAliGator Membre, Modérateur
    22:28 modifié #24
    Et encore pour être rigoureux, il me semble que la plupart des classes Cocoa sont en CopyOnWrite, donc un [... copy] dessus ne les copie pas réellement (même si elles sont mutables) mais pointent sur le même contenu tant que ce dernier n'est modifié par personne (et ce n'est qu'à  la modification (write), si elle survient un jour, que la copie est réellement faite).

    Bon ça c'est under the roof, dans la réalité il vaut mieux se dire que ça fait une vraie copie pour les objets mutables, mais c'est tjs bon à  savoir que c'est optimisé.
  • veveveve Membre
    juin 2007 modifié #25
    dans 1182783638:

    dans 1182783295:

    Comprend pas la, pourquoi les NSString sont retenue 2 fois ? et les NSMutableString 1 fois ?

    Pour moi elle devrai être retenu le meme nombre de fois (NSString et NSMutableString) et 1 seul fois dans ce cas !!!!


    Regarde les adresses... str1 == str3  ;)



    J'ai bien vu ça schlum mais pourquoi retenu "2" fois ? Moi pas comprendre : str1 et str3 devrai etre retenu "1" fois pour moi.
  • AntilogAntilog Membre
    22:28 modifié #26
    Voir les messages précédent:
    str1 et str3 sont le même objet (les adresses sont les mêmes)
    Cet objet est retenu deux fois: une fois en tant que str1 et une fois en qualité de str3.

    Il faut bien que cet unique objet ne soit libéré qu'après que str1 _et_ str2 soient libérés.
  • MulotMulot Membre
    22:28 modifié #27
    ça y est, j'ai reçu "Cocoa par la Pratique", bon j'espère que le fait qu'il soit pour 10.2 n'apportera pas de problème niveau utilisation de certains méthodes et Xcode, ou des nouvelles choses (les binding il me semble, qui sont apparus depuis).
  • schlumschlum Membre
    22:28 modifié #28
    dans 1182955625:

    ça y est, j'ai reçu "Cocoa par la Pratique", bon j'espère que le fait qu'il soit pour 10.2 n'apportera pas de problème niveau utilisation de certains méthodes et Xcode, ou des nouvelles choses (les binding il me semble, qui sont apparus depuis).

    Non, la seule chose qui diffère un peu c'est l'interface de Xcode ; on ne trouve plus tout à  fait les mêmes choses aux mêmes endroits...

    D'ailleurs, dans Xcode 3, ils ont tout chamboulé, j'arrive même plus à  faire un Hello World !  ;D
    Du coup, je me demande comment ça va être pour la 3e édition de Cocoa par la Pratique... Interface Xcode 2 ou Xcode 3  ???

    Pour les bindings, tu auras tout le loisir de voir après comment ça fonctionne... C'est pas nécessaire à  l'apprentissage (d'ailleurs, moi je ne sais pas comment ça fonctionne et je ne les utilise pas... Je n'en suis pas désavantagé pour autant).
  • MulotMulot Membre
    22:28 modifié #29
    Changée à  ce point sous Leopard, moi qui vient de commencer avec la 2.5 !

    Après avoir feuilleté rapidement le bouquin, ça m'a l'air vraiment pas mal, avec des zoulis exemples de tableView qu'il me faudra !
    Bon et bien je vais pouvoir emballer le bouquin pour me l'auto-offrir pour mon anniversaire, comme ça je me concentre encore sur l'Objective-C pendant 2 jours.
  • 22:28 modifié #30
    dans 1182956961:
    Du coup, je me demande comment ça va être pour la 3e édition de Cocoa par la Pratique... Interface Xcode 2 ou Xcode 3  ???

    Le 2.5 pour mettre tout le monde d'accord...
  • schlumschlum Membre
    juin 2007 modifié #31
    dans 1182957269:

    Changée à  ce point sous Leopard, moi qui vient de commencer avec la 2.5 !


    Au niveau d'Interface Builder surtout...
    J'ai pas retrouvé comment instancier mon contrôleur  :o

    (ni comment tester la validité 10.3-10.4 des .nib)
Connectez-vous ou Inscrivez-vous pour répondre.