Gestion de la mémoire, implémentation de constructeurs et mixer ses sources ...
Mulot
Membre
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:
Et voici son implémentation, qui me cause quelques soucis:
Donc j'ai aussi une classe Account et une classe Operation, très similaire à celle-ci.
et l'implémentation que voici:
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.
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 <Cocoa/Cocoa.h><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 /> <br /> //Owner list of account<br /> NSMutableArray * accountTab;<br /> <br /> 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 />// AccountOwner.m<br />// MoneyOrganizer_0.1<br />//<br />// Created by Mulot on 15/06/07.<br />// Copyright 2007 __MyCompanyName__. All rights reserved.<br />//<br /><br />#import "AccountOwner.h"<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 /> lastname = [NSString stringWithString: plastname];<br /> birthday = date;<br /> adress = @"Unknown";<br /> numberOfAccount = 0;<br /> accountTab = [[NSMutableArray alloc] init];<br /> ret = self;<br /> }<br /> <br /> return ret;<br /> <br />} <br /><br />- (void) addAccount: (Account*) anAccount {<br /> <br /> [accountTab insertObject: anAccount atIndex: numberOfAccount];<br /> numberOfAccount++;<br /> <br />}<br /><br />- (Account*) accountAtIndex: (int) index {<br /> <br /> id account = nil;<br /> <br /> if(index >= 0 && index < [accountTab count]){<br /> account =[accountTab objectAtIndex: index];<br /> }<br /> <br /> return account;<br />}<br /><br />- (void) removeAccountAtIndex: (int) index {<br /> <br /> if(index>= 0 && index < [accountTab count]){<br /> [accountTab removeObjectAtIndex: index];<br /> }<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:@"Account Owner \nFirstname : %@\nLastName :%@\nAdress :%@\nBirthday : %@",firstname,lastname,adress ,[birthday description]];<br /><br /> NSEnumerator * enumerator = [accountTab objectEnumerator];<br /> <br /> id account;<br /> NSMutableString * descaccount = [NSMutableString stringWithString:@"\n "];<br /> while( account = [enumerator nextObject]){<br /> <br /> descaccount = [descaccount stringByAppendingString:[account description]];<br /> descaccount = [descaccount stringByAppendingString:@"\n"];<br /> <br /> } <br /> deb = [deb stringByAppendingString: descaccount];<br /><br /> 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 <Cocoa/Cocoa.h><br />#import <Foundation/Foundation.h><br />#import "Operation.h"<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 /> <br /> BOOL accountOwned;<br /> <br /> //The account bank's name<br /> NSString *bankname;<br /> <br /> //The current sum of the account<br /> double currentaccountsum;<br /> <br /> //The amount to be add or sub for valueDates<br /> 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 /> <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 />// Account.m<br />// MoneyOrganizer_0.1<br />//<br />// Created by Mulot on 15/06/07.<br />// Copyright 2007 __MyCompanyName__. All rights reserved.<br />//<br /><br />#import "Account.h"<br /><br />int intSortExpense(id num1, id num2, void *context)<br />{<br /> BOOL v1 = [num1 getExpense];<br /> BOOL v2 = [num2 getExpense];<br /> if (v1 == TRUE && v2 == FALSE)<br /> return NSOrderedAscending;<br /> else if (v2 == TRUE && v1 == FALSE)<br /> return NSOrderedDescending;<br /> else<br /> return NSOrderedSame;<br />}<br /><br />int intSortRevenue(id num1, id num2, void *context)<br />{<br /> BOOL v1 = [num1 getRevenue];<br /> BOOL v2 = [num2 getRevenue];<br /> if (v1 == TRUE && v2 == FALSE)<br /> return NSOrderedAscending;<br /> else if (v2 == TRUE && v1 == FALSE)<br /> return NSOrderedDescending;<br /> else<br /> 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 /> amountToBeAdded = 0.0;<br /> accountOwned = YES;<br /> return self;<br /> }<br /> <br />return nil;<br />}<br /><br />+ (BOOL) addWaitingOperation:(Operation*) operation {<br /> <br /> BOOL result = NO;<br /> <br /> NSDate * actualDate = [NSDate date];<br /> NSDate * operationDate = [operation operationValueDate];<br /> <br /> if(actualDate == [operationDate laterDate: actualDate]){<br /> result = YES;<br /> }<br /> return result;<br />}<br /><br />- (void) addOperation: (Operation*) op { <br /><br /> [operationtab insertObject: op atIndex : numofoperation];<br /> numofoperation++;<br /> <br /> //if the operation is up to be added<br /> if([Account addWaitingOperation:op]){<br /> if([op getExpense]){ <br /> currentaccountsum -= [op getAmount];<br /> }else{<br /> currentaccountsum += [op getAmount];<br /> }<br /> <br /> }else{<br /> if([op getExpense]){ <br /> amountToBeAdded -= [op getAmount];<br /> }else{<br /> amountToBeAdded += [op getAmount];<br /> }<br /> } <br /> [op autorelease];<br /> //Use a selector in order to sort account with the user choosen sorting type<br /> [self sortByOperationDateAsc];<br /> <br />}<br /><br />- (double) amountToBeAdded {<br /> <br /> return amountToBeAdded;<br />}<br /><br />- (void) deleteOperationAtIndex: (int) ind { <br /> <br /> <br /> if(numofoperation >= 0 && ind < [operationtab count]){<br /> numofoperation--;<br /> <br /> Operation * operationToDelete = [operationtab objectAtIndex:ind];<br /> BOOL expense = [operationToDelete getExpense];<br /> <br /> if([Account addWaitingOperation: operationToDelete]){<br /> if(expense){<br /> currentaccountsum += [operationToDelete getAmount];<br /> }else{<br /> currentaccountsum -= [operationToDelete getAmount];<br /> }<br /> }else{<br /> if(expense){<br /> amountToBeAdded += [operationToDelete getAmount];<br /> }else{<br /> amountToBeAdded -= [operationToDelete getAmount];<br /> }<br /> <br /> } <br /> <br /> [operationtab removeObjectAtIndex:ind];<br /> <br /> }<br />}<br /><br />- (AccountOwner*) accountOwner {<br /> <br /> return owner;<br />}<br /><br />- (void) setAccountOwner: (AccountOwner*) ao {<br /> <br /> owner = ao;<br />}<br /><br />- (BOOL) isOwned {<br /> <br /> return accountOwned; <br />}<br /><br />- (void) setOwned: (BOOL) boolean {<br /> <br /> accountOwned = boolean;<br />}<br /><br />- (Operation*) getOperationAtIndex: (int) ind { <br /> <br /> return [operationtab objectAtIndex:ind];<br />}<br /><br />- (void) sortByOperationValueAsc { <br /> <br /> NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"op_amount"ascending:YES] autorelease];<br /> NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br /> <br /> operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br />}<br /><br />- (void) sortByOperationValueDesc { <br /> <br /> NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"op_amount"ascending:NO] autorelease];<br /> NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br /> <br /> operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br />}<br /><br />- (void) sortByOperationDateAsc { <br /> <br /> NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"op_date"ascending:YES] autorelease];<br /> NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br /> <br /> operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br />}<br /><br />- (void) sortByOperationDateDesc { <br /> <br /> NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"op_date"ascending:NO] autorelease];<br /> NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br /> <br /> operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br />}<br /><br />- (void) sortByOperationNameAsc { <br /> <br /> NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"op_designation"ascending:YES] autorelease];<br /> NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br /> <br /> operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br /> <br />}<br /><br />- (void) sortByOperationNameDesc { <br /> <br /> NSSortDescriptor * lastNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"op_designation"ascending:NO] autorelease];<br /> <br /> NSArray * sortDescriptors = [NSArray arrayWithObject:lastNameDescriptor];<br /> <br /> operationtab = [operationtab sortedArrayUsingDescriptors:sortDescriptors];<br /> <br />}<br /><br />- (void) sortByExpense {<br /> <br /> operationtab = [operationtab sortedArrayUsingFunction:intSortExpense context:NULL];<br /><br />}<br /><br />- (void) sortByRevenue{<br /> <br /> operationtab = [operationtab sortedArrayUsingFunction:intSortRevenue context:NULL];<br /><br />}<br /><br />- (int) getRetainCountAtIndex: (int) ind {<br /> <br /> int nb;<br /> <br /> if( [operationtab count] > 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:@"Acount description : \nBank: %@\nName: %@ \nAmount: %.2f \nAmount waiting: %.2f\n\n",bankname,accountname,[self getCurrentAccountSum],amountToBeAdded];<br /><br /> while(operation = [enumerator nextObject]){<br /> begining = [begining stringByAppendingString:@"\n"];<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 /> <br /> return currentaccountsum;<br />}<br /> <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.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
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
La tradition en objective-C serait plutôt les noms
- (NSString*) firstName ;
- (NSString*) lastName ;
- (NSString*) adress ;
- (NSDate*) birthDay ;
pour les accessors methods
La variable ret ne sert à rien. renvoyer self
addObject n'est-elle pas une méthode suffisante ?
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.
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:
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 ?
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.
Par contre j'ai encore un doute qui subsiste, au niveau de l'autorelease Pool :
Voici ma petite classe :
et mon main:
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.
-> leak : tu alloues une date, puis tu remplaces le pointeur dessus par une copie d'un autre objet !
Et par ailleurs, inutile de faire des copies de chaà®nes :
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...
Je te conseille de compulser "Cocoa par la pratique"
Gestion de la mémoire en Objective-C
Pas besoin d'autorelease ; il y a les constructeurs de commodité pour ça...
[NSString stringWithString:@ZEVITCH];
Rien compris...
Il est statique ; il n'y a pas d'init.
Il ne faut surtout pas faire ça ; un constructeur n'a pas à envoyer un release à ses arguments !
Si c'est objets sont non mutable, il faut sans conteste se contenter de faire un retain dessus.
Pour un mutable, envisager la copie...
Non, pas besoin d'AutoReleasePool dans la description. Pour le reste, cf. au-dessus...
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
Donc dans mon constructeur version "normale", je fais juste:
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à ...
- (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;
}
Tout simplement...
[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.
(qui en plus va faire des tests sur la mutabilité etc...)
/* 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
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
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é !
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.
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é.
J'ai bien vu ça schlum mais pourquoi retenu "2" fois ? Moi pas comprendre : str1 et str3 devrai etre retenu "1" fois pour moi.
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.
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).
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.
Le 2.5 pour mettre tout le monde d'accord...
Au niveau d'Interface Builder surtout...
J'ai pas retrouvé comment instancier mon contrôleurÂ
(ni comment tester la validité 10.3-10.4 des .nib)