# NSMutabbleArray



## esbeone (22 Septembre 2010)

Bonjour à tous,

J'ai des fuites mémoire dans mon application.

J'ai une classe Demande avec des propriétés définies par property/synthesize.

J'ajoute des objets de type Demande dans un tableau. Ce tableau est déclaré dans le appDelegate avec property/synthesize. Il est remplit une première fois lorsque l'app a finit de se lancer (appDidFinishLaunching):

...
Demande *dem =[[Demande alloc] init];		
		dem.demTitle=titre;
		dem.demId=Id;
[tab_Demandes addObject:dem];
[dem release];
...

Je souhaite plus tard re-remplir ce tableau.

Cela se fait dans la classe MyTableViewController:

[[appDelegate tab_Demandes] removeAllObjects];
...
Demande *dem =[[Demande alloc] init];		
		dem.demTitle=titre;
		dem.demId=Id;
		dem.demCreated=created;
[[appDelegate tab_Demandes] addObject:dem]; 
[dem release];
...

Je veux faire un [[appDelegate tab_Demandes] removeAllObjects] depuisTableViewController avant de re remplir mon tableau pour effacer les demandes ajoutées dans appDelegate. Mais mon appli plante sur le remove: bad_access.

Si je ne fais pas de remove, je n'ai pas de fuites mémoire mais mes demandes sont alors en double.

Si je ne fais pas de  [dem release] dans appDelegate alors je peux faire un remove dans TableViewController et mon tableau est ok. Mais alors j'ai une fuite mémoire: autant que le nombre de dem non releasées.

Si je release dem : pas de fuites, pas de remove donc demandes en double
Si je ne release pas dem : remove fonctionne, tableau ok mais fuites.

Je peux faire un [[appDelegate tab_Demandes] removeAllObjects] depuis appDelegate mais pas depuis une autre classe.

J'espère avoir été clair, je ne comprends pas trop ce qui se passe en fait.

C'est ma première app. 

Merci pour toute aide.


----------



## Céroce (23 Septembre 2010)

C'est difficile de répondre sans voir plus de code, mais ce que tu fais est bon: les classes de collection (NSArray, NSDictionary, NSSet et leur versions Mutables) retiennent les objets qu'elle contiennent. Après avoir ajouté un objet que tu viens d'allouer, il faut donc bien le libérer comme tu le fais.

Tu peux essayer d'activer le NSZombie pour mieux comprendre ce qui se passe.

Essaye aussi de lancer une analyse statique du code (sous XCode: menu Build > Build & Analyze).

P.S.: Je te recommande de ne pas utiliser les propriétés tant que tu ne comprends pas exactement quel code elles génèrent.


----------



## esbeone (23 Septembre 2010)

Bonjour Céroce,

on est presque voisin , j'habite à Gouvieux.

Le build and analyse n'a pas trouvé de leaks.

En ce qui concerne les propriétés, j'ai essayé en déclarant le tableau externe mais les fuites persistent et je ne peux pas faire de removeAllObjects sur mon tableau.

C'est ma première appli, c'est un peu difficile cette gestion mémoire. Je suis .Net c# à la base.

Peut être je peux t'envoyer mon projet en MP?


----------



## Nyx0uf (23 Septembre 2010)

Passe ton array en ivar dans ton viewcontroller, plutôt que de faire des [appDelegate monArray].

Et sinon y aurait pas un accès concurrent sur ton tableau par hasard ? Plus de code nous aiderait.


----------



## esbeone (23 Septembre 2010)

Je vais vous expliquer plus en détails mon problème avec mon code:

Demande.h:


```
@interface Demande : NSObject {
	
	//attibuts de la classe demande
	NSString *demId;
	NSString *demStatut;
	NSString *demTitle;
	NSString *demCreated;
	NSString *demIdCopro;
	NSString *demIdImmeuble;
	NSString *demIdLot;
	NSString *demDescriptif;
	NSString *demAuteur;
	NSString *demIdAuteur;
	NSString *demLoginAuteur;	
}
@property (retain,nonatomic) NSString *demId;
@property (retain,nonatomic) NSString *demIdCopro;
@property (retain,nonatomic) NSString *demIdImmeuble;
@property (retain,nonatomic) NSString *demIdLot;
@property (retain,nonatomic) NSString *demDescriptif;
@property (retain,nonatomic) NSString *demStatut;
@property (retain,nonatomic) NSString *demTitle;
@property (retain,nonatomic) NSString *demCreated;
@property (retain,nonatomic) NSString *demAuteur;
@property (retain,nonatomic) NSString *demIdAuteur;
@property (retain,nonatomic) NSString *demLoginAuteur;
@end
```

Demande.m:

```
@implementation Demande

@synthesize demId,demIdCopro,demIdImmeuble,demIdLot,demDescriptif,demStatut,demTitle,demCreated,demAuteur,demIdAuteur,demLoginAuteur;


- (void)dealloc {	
	[demId release];
	[demIdCopro release];
	[demId release];
	[demIdImmeuble release];
	[demIdLot release];
	[demDescriptif release];
	[demStatut release];
	[demTitle release];
	[demCreated release];
	[demAuteur release];
	[demIdAuteur release];
	[demLoginAuteur release];
	
	
	[super dealloc];
}

@end
```


appDelegate:
Mon application une fois chargée fait une requête et recoit un json. je parse le json et ajoute les objets demande dans tab_Demandes.
Ensuite la tableView est chargée avec des custom cell.


Dans appDelegate.h:


```
NSMutableArray *tab_Demandes;
@property (nonatomic,retain) NSMutableArray *tab_Demandes;
```

Dans appDelegate.m:

```
@synthesize tab_Demandes
- (void)requestDDone:(ASIHTTPRequest *)request
{
	
	NSData *responseData = [request responseData];		
	//Stocke les données dans jsonstring
	NSString *jsonString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
	//NSLog(@"JSON: %@",jsonString);	
	
	//Crée un dictionnaire à partir du json string
	NSDictionary *results = [jsonString JSONValue];
	
	//stocke dans un tableau chaque objet du dictionnaire
	NSArray *demandes = [results objectForKey:@"Demandes"];		
	
	for (NSDictionary *demandeD in demandes)
	{
				
		//parse du JSON
		NSString *title = [demandeD objectForKey:@"Title"];
		NSString *titre = [title stringByReplacingPercentEscapesUsingEncoding:
						   NSASCIIStringEncoding];
		
		NSString *description = [demandeD objectForKey:@"Description"];
		NSString *descriptif = [description stringByReplacingPercentEscapesUsingEncoding:
									  NSASCIIStringEncoding];

		NSString *Id = [demandeD objectForKey:@"Id"];
		NSString *created = [demandeD objectForKey:@"Created"];
		NSString *statut = [demandeD objectForKey:@"Statut"];
		NSString *copropriete = [demandeD objectForKey:@"Copropriete"];
		NSString *immeuble = [demandeD objectForKey:@"Immeuble"];
		NSString *lot = [demandeD objectForKey:@"Lot"];
		NSString *auteur = [demandeD objectForKey:@"Author"];
		NSString *auteurId = [demandeD objectForKey:@"IdAuthor"];
		NSString *auteurLogin = [demandeD objectForKey:@"Login"];
		
		//Creation de l'objet
		Demande *dem =[[Demande alloc] init];		
		dem.demTitle=titre;
		dem.demId=Id;
		dem.demCreated=created;
		dem.demDescriptif=descriptif;
		dem.demIdCopro=copropriete;
		dem.demIdImmeuble=immeuble;
		dem.demIdLot=lot;
		dem.demStatut=statut;
		dem.demAuteur=auteur;
		dem.demIdAuteur=auteurId;
		dem.demLoginAuteur=auteurLogin;	
		
		[tab_Demandes addObject:dem];
				
		[dem release];
	
	}
	[jsonString release];	
}
```

Customcell dans MytableViewController.m:


```
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
	
	
	static NSString *CellIdentifier = @"Cell";
    
    CustomCellViewController *cell = (CustomCellViewController *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
	{
       // NSLog(@"Cell created");
		NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomCellViewController" owner:nil options:nil];
		
		for(id currentObject in topLevelObjects)
		{
			if([currentObject isKindOfClass:[CustomCellViewController class]])
			{
				cell = (CustomCellViewController *)currentObject;
				break;
			}
		}
	}
		
		// Set up the cell...

	
		TabsAppDelegate *appDelegate = (TabsAppDelegate*)[[UIApplication sharedApplication] delegate];
	
		cell.lbl_demId.text=[NSString stringWithFormat:@"%@", [[[appDelegate tab_Demandes] objectAtIndex:indexPath.row ] demId]];
		
	
		cell.lbl_demCopro .text=[NSString stringWithFormat:@"%@", [[[appDelegate tab_Demandes] objectAtIndex:indexPath.row] demIdCopro ]];
		cell.lbl_demImmeuble.text=[NSString stringWithFormat:@"%@", [[[appDelegate tab_Demandes] objectAtIndex:indexPath.row] demIdImmeuble]];
		cell.lbl_demLot.text=[NSString stringWithFormat:@"%@", [[[appDelegate tab_Demandes] objectAtIndex:indexPath.row] demIdLot]];
		cell.lbl_demDescriptif.text=[NSString stringWithFormat:@"%@", [[[appDelegate tab_Demandes] objectAtIndex:indexPath.row] demTitle]];
		//NSLog(@"statut demande : %@",[[tab_Demandes objectAtIndex:indexPath.row] demStatut]);
		if ([[[[appDelegate tab_Demandes] objectAtIndex:indexPath.row] demStatut] isEqualToString: @"Validée"])
		{
		cell.lbl_ImageView.image=[UIImage imageNamed:@"VDEM2.png"];
		}
		if([[[[appDelegate tab_Demandes] objectAtIndex:indexPath.row] demStatut] isEqualToString: @"Initiée"])
		{
		   cell.lbl_ImageView.image=[UIImage imageNamed:@"IDEM.png"];
		}
		if([[[[appDelegate tab_Demandes] objectAtIndex:indexPath.row] demStatut] isEqualToString: @"Terminée"])
		{
		cell.lbl_ImageView.image=[UIImage imageNamed:@"TDEM.png"];
		}
		if([[[[appDelegate tab_Demandes] objectAtIndex:indexPath.row] demStatut] isEqualToString: @"En coursée"])
		{
		cell.lbl_ImageView.image=[UIImage imageNamed:@"EDEM.png"];
	 
		}

	
	return cell;
	   
}
```


Chaque fois que je clique sur une ligne de la table , j'accède aux infos de la demande dans une vue specifique.

Quand je fais"back" et revient à la tableView je refais une requete pour rafraichir la liste des demandes.

Dans MyTableViewController.m:

```
- (void)requestDReloadDone:(ASIHTTPRequest *)request
{

	TabsAppDelegate *appDelegate = (TabsAppDelegate*)[[UIApplication sharedApplication] delegate];
	
	NSData *responseData = [request responseData];	
	
	//Stocke les données dans jsonstring
	NSString *jsonString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
	//NSLog(@"JSON: %@",jsonString);
	//Crée un dictionnaire à partir du json string
	NSDictionary *results = [jsonString JSONValue];
	//stocke dans un tableau chaque objet du dictionnaire
	NSArray *demandes = [results objectForKey:@"Demandes"];			

	//[[appDelegate tab_Demandes] removeAllObjects]; //PLANTAGE	
	
	for (NSDictionary *demandeD in demandes)
	{		
		//parse du JSON
		NSString *titre = [demandeD objectForKey:@"Title"];
		NSString *desriptif = [demandeD objectForKey:@"Description"];
		NSString *Id = [demandeD objectForKey:@"Id"];
		NSString *created = [demandeD objectForKey:@"Created"];
		NSString *statut = [demandeD objectForKey:@"Statut"];
		NSString *copropriete = [demandeD objectForKey:@"Copropriete"];
		NSString *immeuble = [demandeD objectForKey:@"Immeuble"];
		NSString *lot = [demandeD objectForKey:@"Lot"];
		NSString *auteur = [demandeD objectForKey:@"Author"];
		NSString *auteurId = [demandeD objectForKey:@"IdAuthor"];
		NSString *auteurLogin = [demandeD objectForKey:@"Login"];
		
		//Creation de l'objet
		Demande *dem =[[Demande alloc] init];		
		dem.demTitle=titre;
		dem.demId=Id;
		dem.demCreated=created;
		
		NSString *descriptifDecode = [desriptif stringByReplacingPercentEscapesUsingEncoding:
									  NSASCIIStringEncoding];		//gestion des accents
		
		dem.demDescriptif=descriptifDecode;
		dem.demIdCopro=copropriete;
		dem.demIdImmeuble=immeuble;
		dem.demIdLot=lot;
		dem.demStatut=statut;
		dem.demAuteur=auteur;
		dem.demIdAuteur=auteurId;
		dem.demLoginAuteur=auteurLogin;
	
		[[appDelegate tab_Demandes] addObject:dem];
		
		[dem release];
	}
	
	
	//on fait apparaitre la vue	
	[super viewWillAppear:YES];
	[tableV reloadData];
	
	[jsonString release];
}
```
Ce code est redondant, similaire à celui dans appDelegate. Si j'appelle la méthode qui est dans appDelegate le problème est le même. J'ai besoin de faire un reloadData sur TableV qui est ma tableView. Elle est déclarée dansMyTabvleViewController.h:

```
IBOutlet UITableView *tableV;
```

Si je ne release pas l'objet demande [dem release]; je peux par la suite faire [[appDelegate tab_Demandes] removeAllObjects]. mais les objets dem sont leaked.

Si je fais [dem release] alors je ne peux plus faire [appDelegate tab_Demandes] removeAllObjects]. Je n'ai plus de fuites mais j'ai les anciennes demandes dans tab_Demandes.


NyxOuf je pense que c'est un accès concurrent. Je viens de remarquer que je peux faire un [appDelegate tab_Demandes] removeAllObjects] dans appDelegate mais pas depuis MytableViewController.m . 

"Passe ton array en ivar dans ton viewcontroller"? tu veux dire quoi par là? 

Je suis newbie en objective-C.


----------



## Nyx0uf (23 Septembre 2010)

Pourquoi tu gères ton array dans le AppDelegate et pas dans ton ViewController, alors que c'est ici que tu en as besoin ? Tu t'embêtes là... et ça fait du code vachement redondant.


Dans ton MytableViewController.h


```
NSMutableArray* tableau;
```

MytableViewController.h


```
-(void)viewDidLoad
{
   tableau = [[NSMUtableArray alloc] init];
}
-(void)dealloc
{
   [tableau release];
}
```

Et y a aucune raison d'appeller [super viewWillAppear:animated]; dans un callback.


----------



## esbeone (23 Septembre 2010)

je fais les modifs et je te tiens au courant

merci

---------- Nouveau message ajouté à 13h06 ---------- Le message précédent a été envoyé à 11h56 ----------

j'ai fais les modifs.

1) quand mon app se lance ma tableView reste vide. Par contre après être allé sur une autre vue, quand je reviens sur la tableView celle ci se peuple.

2)le même problème persiste. Je ne peux pas faire de removeAllObjects : 


```
- (void)requestDReloadDone:(ASIHTTPRequest *)request
{

	NSData *responseData = [request responseData];	
	
	//Stocke les données dans jsonstring
	NSString *jsonString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
	//NSLog(@"JSON: %@",jsonString);
	//Crée un dictionnaire à partir du json string
	NSDictionary *results = [jsonString JSONValue];
	//stocke dans un tableau chaque objet du dictionnaire
	NSArray *demandes = [results objectForKey:@"Demandes"];	

	[tab_Demandes removeAllObjects]; PLANTAGE
	
	for (NSDictionary *demandeD in demandes)
	{
	
		//parse du JSON
		NSString *titre = [demandeD objectForKey:@"Title"];
		NSString *desriptif = [demandeD objectForKey:@"Description"];
		NSString *Id = [demandeD objectForKey:@"Id"];
		NSString *created = [demandeD objectForKey:@"Created"];
		NSString *statut = [demandeD objectForKey:@"Statut"];
		NSString *copropriete = [demandeD objectForKey:@"Copropriete"];
		NSString *immeuble = [demandeD objectForKey:@"Immeuble"];
		NSString *lot = [demandeD objectForKey:@"Lot"];
		NSString *auteur = [demandeD objectForKey:@"Author"];
		NSString *auteurId = [demandeD objectForKey:@"IdAuthor"];
		NSString *auteurLogin = [demandeD objectForKey:@"Login"];
		
		//Creation de l'objet
		Demande *dem =[[Demande alloc] init];		
		dem.demTitle=titre;
		dem.demId=Id;
		dem.demCreated=created;
		
		NSString *descriptifDecode = [desriptif stringByReplacingPercentEscapesUsingEncoding:
									  NSASCIIStringEncoding];		//gestion des accents
		
		dem.demDescriptif=descriptifDecode;
		dem.demIdCopro=copropriete;
		dem.demIdImmeuble=immeuble;
		dem.demIdLot=lot;
		dem.demStatut=statut;
		dem.demAuteur=auteur;
		dem.demIdAuteur=auteurId;
		dem.demLoginAuteur=auteurLogin;
	
		[tab_Demandes addObject:dem];
		
		[dem release];
	}	
	//on fait apparaitre la vue	
	[super viewWillAppear:YES];
	NSLog(@"nb de demandes dans tab_demandes,fin boucle ajout: %d",[tab_Demandes count]);
	[tableV reloadData];	
	[jsonString release];
}

- (void)dealloc {
	[tab_Demandes release];
    [super dealloc];
}
```


----------



## Nyx0uf (23 Septembre 2010)

1 - Fais un [self.tableView reloadData]; quand t'as finis de remplir ton tableau.

2 - Il dit quoi le debugger ?


----------



## esbeone (23 Septembre 2010)

1) Merci. Je faisais un relaodData mais au mauvais endroit avec les modifs de code précédentes. De même l'alloc et init du tableau tab_Demandes étaient fausses. Maintenant ça marche au lancement de l'appli.

2) l'application se comporte différemment. je peux maintenant faire removeAllObjects en ayant fait un [dem release] auparavant. il y a toujours des fuites. je reviens quand j'ai compris un peu plus ce qui se passe maintenant.

---------- Nouveau message ajouté à 15h00 ---------- Le message précédent a été envoyé à 14h49 ----------

Je n'ai pas beaucoup de temps cet après midi à consacrer à l'appli iPhone.

Je peux enfin faire un removeAllObjects et releaser les éléments que j'insère dans le tableau.

Il me reste une fuite. C'est une nouvelle. Elle concerne le tableau tab_Demandes ainsi que les objets contenus dans le tableau. 

Je dois faire alloc et release au mauvais endroit. Je vais fouiller en fin de journée. Sinon demain matin je reviendrai.

Merci encore.


----------



## BooBoo (23 Septembre 2010)

J'ai suivi ton pb de loin...
Le problème corrigé était lequel ?
le release était avant le alloc/init ?


----------



## esbeone (23 Septembre 2010)

problème corrigé:

j'instanciais des objets, j&#8217;insérais ces objets dans un tableau, je les "release" et après je ne pouvais plus faire de "removeallObjects" sur le tableau. Je faisais cela dans le appDelegate ainsi que dans tableViewController.

Le fait de déclarer le tableau dans la tableViewController et non dans le appDelegate m'a permis de faire "removeAllObjects", ce que m'a conseillé Nyx0uf. D'ailleurs les traitements sur le tableau peuvent se faire dans le tableViewcontroller uniquement. Je comprenais mal le lancement de l'appli.

Ensuite avec le changement de déclaration du tableau, ma tableview ne se peuplait pas.
J'ai déplacé le "tableView reloadData" et l'alloc/init du tab_Demandes.
Maintenant ça fonctionne. Toujours d'après Nyx0uf.


Nouveau problème : 


Maintenant j'ai une nouvelle leak mémoire sur le tableau. Je n'ai pas eu encore le temps de regarder.


----------



## esbeone (24 Septembre 2010)

Je suis de retour ;-)

Bon en fait mon problème d'hier n'est pas réglé, ce que je croyais hier soir. J'ai été un peu vite, j'avais pas le temps de regarder vraiment en détail.

Voici mon code simplifié (c'est bcp plus simple maintenant, merci NyxOuf) :

tab_Demandes est déclaré dans MyTableViewController.h sans property :

NSMutableArray *tab_Demandes;


```
- (void)viewWillAppear:(BOOL)animated 
{	
    if(firstLaunch==TRUE) 
	{
		tab_Demandes=[[NSMutableArray alloc]init]; 
		[self demandesReload_grabURL];		
		firstLaunch=FALSE;
	}
	else {
		[tab_Demandes removeAllObjects];  //----- PLANTAGE
		[self demandesReload_grabURL];		
	}		
}

- (void)requestDReloadDone:(ASIHTTPRequest *)request
{	
	
	NSData *responseData = [request responseData];		
	//Stocke les données dans jsonstring
	NSString *jsonString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

	//Crée un dictionnaire à partir du json string
	NSDictionary *results = [jsonString JSONValue];
	//stocke dans un tableau chaque objet du dictionnaire
	NSArray *demandes = [results objectForKey:@"Demandes"];	
	
	for (NSDictionary *demandeD in demandes)
	{

		//parse du JSON
		NSString *titre = [demandeD objectForKey:@"Title"];
		NSString *desriptif = [demandeD objectForKey:@"Description"];
		NSString *Id = [demandeD objectForKey:@"Id"];
		NSString *created = [demandeD objectForKey:@"Created"];
		
		
		//Creation de l'objet
		Demande *dem =[[Demande alloc] init];		
		dem.demTitle=titre;
		dem.demId=Id;
		dem.demCreated=created;
		
		NSString *descriptifDecode = [desriptif stringByReplacingPercentEscapesUsingEncoding:
									  NSASCIIStringEncoding];		//gestion des accents
		
		dem.demDescriptif=descriptifDecode;
	
		[tab_Demandes addObject:dem];
		
		[dem release];
	}
	
	
	//on fait apparaitre la vue	
	[super viewWillAppear:YES];

	[tableV reloadData];
	
	[jsonString release];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {   
	return [tab_Demandes count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 	
	static NSString *CellIdentifier = @"Cell";    
    CustomCellViewController *cell = (CustomCellViewController *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
	{
       // NSLog(@"Cell created");
		NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomCellViewController" owner:nil options:nil];
		
		for(id currentObject in topLevelObjects)
		{
			if([currentObject isKindOfClass:[CustomCellViewController class]])
			{
				cell = (CustomCellViewController *)currentObject;
				break;
			}
		}
	}		
		// Set up the cell...	
			
		cell.lbl_demId.text=[NSString stringWithFormat:@"%@", [[tab_Demandes objectAtIndex:indexPath.row ] demId]];	
		cell.lbl_demCopro .text=[NSString stringWithFormat:@"%@", [[tab_Demandes objectAtIndex:indexPath.row] demIdCopro ]];
		cell.lbl_demImmeuble.text=[NSString stringWithFormat:@"%@", [[tab_Demandes objectAtIndex:indexPath.row] demIdImmeuble]];
		cell.lbl_demLot.text=[NSString stringWithFormat:@"%@", [[tab_Demandes objectAtIndex:indexPath.row] demIdLot]];
		cell.lbl_demDescriptif.text=[NSString stringWithFormat:@"%@", [[tab_Demandes objectAtIndex:indexPath.row] demTitle]];
		if ([[[tab_Demandes objectAtIndex:indexPath.row] demStatut] isEqualToString: @"Validée"])
		{
		cell.lbl_ImageView.image=[UIImage imageNamed:@"VDEM2.png"];
		}
		if([[[tab_Demandes objectAtIndex:indexPath.row] demStatut] isEqualToString: @"Initiée"])
		{
		   cell.lbl_ImageView.image=[UIImage imageNamed:@"IDEM.png"];
		}
		if([[[tab_Demandes objectAtIndex:indexPath.row] demStatut] isEqualToString: @"Terminée"])
		{
		cell.lbl_ImageView.image=[UIImage imageNamed:@"TDEM.png"];
		}
		if([[[tab_Demandes objectAtIndex:indexPath.row] demStatut] isEqualToString: @"En coursée"])
		{
		cell.lbl_ImageView.image=[UIImage imageNamed:@"EDEM.png"];
	 
		}	
	return cell;
	   
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	
	//assignation de la variable globale demSelected
	demSelected=[tab_Demandes objectAtIndex:indexPath.row];	
	
	//le navigation controller pousse la view detailviewcontroller
	DetailViewController *newView =[[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
	[self.navigationController pushViewController: newView animated:YES ];
	
	[newView release];	
}


- (void)dealloc {
    [tab_Demandes release];
    [super dealloc];
}
```

voilà mon code.

Le premier chargement de la tableView marche nickel.
C'est quand je reviens sur cette vue, après avoir clické sur une ligne par exemple et je fais "back" que le problème arrive.

Je dois vider et recharger mon tableau servant à peupler la tableView.

removeAllObjects plante dans viewWillAppear. Comme ci quelque chose release les objets avant ou alors quelque chose "pointe" sur les objets du tableau ...

si vous avez une petite idée je testerai volontiers.


----------



## Nyx0uf (24 Septembre 2010)

1 - Pour ton BOOL, c'est YES ou NO.

2 - init ton tableau dans viewDidLoad plutôt que viewWillAppear: vu que cette dernière est appelée chaque fois que la vue se charge, ça t'évitera un if.

3 - Dans ta méthode requestDReloadDone: ne fais pas de [super viewWillAppear:], Ca n'a strictement rien à faire ici, ta vue est déjà apparue à ce moment là.


----------



## esbeone (24 Septembre 2010)

ok merci pour ces conseils.

Je crois avoir trouvé une piste :

Ma classe Demande:


```
@interface Demande : NSObject {	
	//attibuts de la classe demande
	NSString *demId;
	NSString *demStatut;
	NSString *demTitle;
	NSString *demCreated;
	NSString *demIdCopro;
	NSString *demIdImmeuble;
	NSString *demIdLot;
	NSString *demDescriptif;
	NSString *demAuteur;
	NSString *demIdAuteur;
	NSString *demLoginAuteur;	
}
@property (retain,nonatomic) NSString *demId;
@property (retain,nonatomic) NSString *demIdCopro;
@property (retain,nonatomic) NSString *demIdImmeuble;
@property (retain,nonatomic) NSString *demIdLot;
@property (retain,nonatomic) NSString *demDescriptif;
@property (retain,nonatomic) NSString *demStatut;
@property (retain,nonatomic) NSString *demTitle;
@property (retain,nonatomic) NSString *demCreated;
@property (retain,nonatomic) NSString *demAuteur;
@property (retain,nonatomic) NSString *demIdAuteur;
@property (retain,nonatomic) NSString *demLoginAuteur; 
@end


#import "Demande.h"
@implementation Demande

@synthesize demId,demIdCopro,demIdImmeuble,demIdLot,demDescriptif,demStatut,demTitle,demCreated,demAuteur,demIdAuteur,demLoginAuteur;

- (void)dealloc {	
/*
	[demId release];
	[demIdCopro release];
	[demId release];
	[demIdImmeuble release];
	[demIdLot release];
	[demDescriptif release];
	[demStatut release];
	[demTitle release];
	[demCreated release];
	[demAuteur release];
	[demIdAuteur release];
	[demLoginAuteur release];	 
	[super dealloc];
*/
}
@end
```


Si je ne release pas les attributs de la demande dans le dealloc (comme ci-dessus) alors je peux faire un removeAllObjects  depuis MyTableViewController. Je n'ai plus de fuites au niveau des objets insérés dans le tableau.

Mais alors ces strings ne sont jamais release. Et j'ai donc autant de fuites sur des strings que de demandes*les attributs_de_la_demande.

Je pense que le removeAllObject essaie de liberer les attributs de l'objets demande et que s'ils ont déjà été release alors l'appli plante.


----------



## Nyx0uf (24 Septembre 2010)

Ton dealloc est correct, ta classe Demande semble correct, peut-être mettre des copy, au lieu de retain dans tes properties.

Tu devrais probablement lire ça : http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html


----------



## esbeone (24 Septembre 2010)

le copy dans les properties n'a pas fonctionné.

je vais regarder le lien que tu m'as donné.

en attendant d'autres idées arrivent je testerai volontiers direct.

---------- Nouveau message ajouté à 14h25 ---------- Le message précédent a été envoyé à 13h57 ----------

Est ce que les properties de l'objet dem sont released quand je fais dem release ? Mon tab_Demandes ne contient que des pointeurs donc cela peut venir de là?


----------



## Nyx0uf (24 Septembre 2010)

Quand tu envoies le message release à un objet le compteur de références et décrémenté de 1, quand il arrive à 0 ton objet reçoit le message dealloc, donc release les attributs.


----------



## esbeone (24 Septembre 2010)

quand je fais addObject c'est un pointeur qui est ajouté au tableau non? donc quand je fais dem release alors les pointeurs du tableau ne pointent vers rien et le removeAllobject plante !? est ce correct ?


----------



## BooBoo (24 Septembre 2010)

La console n'indique rien quand ca plante ?

pour ma part, je ferais le removeAllObjects dans le requestDReloadDone, mais ca ne doit rien changer...


----------



## esbeone (24 Septembre 2010)

la console indique bad_access. le remove dans le requestDone ne change rien malheureusement.
C'est bizarre ce bug.


----------



## Nyx0uf (24 Septembre 2010)

Bha le debugger il raconte quoi ?


----------



## BooBoo (24 Septembre 2010)

esbeone a dit:


> quand je fais addObject c'est un pointeur qui est ajouté au tableau non? donc quand je fais dem release alors les pointeurs du tableau ne pointent vers rien et le removeAllobject plante !? est ce correct ?



Le addObject fait un retain qui incremente le compteur de référence.
Le removeAllObject fait un release sur tous les objets qui decremente le comteur de référence. Si le compteur arrive à 0, alors le dealloc est appelé.

Tu dis que en enlevant les release des property de Demande, ca fonctionne.
Le problème doit donc être la dessus car le dealloc est appelé (le compteur de référence arrive à 0)

Mais je ne vois pas le probleme

Mais tous les champs de Demande ne sont pas renseigné...
il faudrait peut être faire:
if (demIdCopro) {
  [demIdCopro release];
}

mais je ne suis pas chez moi pour faire le test...


----------



## esbeone (24 Septembre 2010)

est ce que le fait de changer de vue , lorsque je clique sur une ligne de la tableView, fait un release sur le tableau?


----------



## Nyx0uf (24 Septembre 2010)

Bha t'envoies sans doute un message à une instance désallouée.


----------



## BooBoo (24 Septembre 2010)

esbeone a dit:


> est ce que le fait de changer de vue , lorsque je clique sur une ligne de la tableView, fait un release sur le tableau?



non. La vue existe encore. Il y a juste des notifications (view will/did disappear)


----------



## esbeone (24 Septembre 2010)

si j'ajoute des objets demande sans attibuts  :


```
Demande *dem =[[Demande alloc] init];
	/*
		dem.demTitle=[demandeD objectForKey:@"Title"];	
		dem.demId=[demandeD objectForKey:@"Id"];
		dem.demCreated=[demandeD objectForKey:@"Created"];
		dem.demDescriptif=[demandeD objectForKey:@"Description"];
		dem.demIdCopro=[demandeD objectForKey:@"Copropriete"];
		dem.demIdImmeuble=[demandeD objectForKey:@"Immeuble"];
		dem.demIdLot=[demandeD objectForKey:@"Lot"];
		dem.demStatut=[demandeD objectForKey:@"Statut"];;
		dem.demAuteur=[demandeD objectForKey:@"Author"];;
		dem.demIdAuteur=[demandeD objectForKey:@"IdAuthor"];;
		dem.demLoginAuteur=[demandeD objectForKey:@"Login"];;
		*/
			
		[tab_Demandes addObject:dem];		
		[dem release];
```

alors là je n'ai plus de crash ou de fuites mémoire. Je peux faire un removeAllObjects du tableau

j'ai un problème de retain/release/dealloc sur les properties de mes objets dem ajoutés au tableau

---------- Nouveau message ajouté à 18h03 ---------- Le message précédent a été envoyé à 16h40 ----------

Si je fais "ma boucle add:Object puis removeAllObjects" plusieurs fois pour le premier chargement ça ne plante pas.

C'est une fois que je clicke sur une ligne puis revient sur la table avec le bouton "back" que le problème survient.


```
//décrit ce qui se passe lorsqu'une cellule de la table est touched 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Navigation logic may go here. Create and push another view controller.
	// AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];
	// [self.navigationController pushViewController:anotherViewController];
	// [anotherViewController release];		
	
	//assignation de la variable demSelected
	demSelected=[tab_Demandes objectAtIndex:indexPath.row];	
	
	//le navigation controller pousse la view detailviewcontroller
	DetailViewController *newView =[[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
	[self.navigationController pushViewController: newView animated:YES ];
	
	[newView release];		
		}
```

demselected est une variable globale dans le appDelegate

Ma méthode de construction des cells:

```
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 	
	
	static NSString *CellIdentifier = @"Cell";    
    CustomCellViewController *cell = (CustomCellViewController *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
	{
       // NSLog(@"Cell created");
		NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CustomCellViewController" owner:nil options:nil];
		
		for(id currentObject in topLevelObjects)
		{
			if([currentObject isKindOfClass:[CustomCellViewController class]])
			{
				cell = (CustomCellViewController *)currentObject;
				break;
			}
		}
	}
		
		// Set up the cell...	
			
		cell.lbl_demId.text=[NSString stringWithFormat:@"%@", [[tab_Demandes objectAtIndex:indexPath.row ] demId]];	
		cell.lbl_demCopro .text=[NSString stringWithFormat:@"%@", [[tab_Demandes objectAtIndex:indexPath.row] demIdCopro ]];
		cell.lbl_demImmeuble.text=[NSString stringWithFormat:@"%@", [[tab_Demandes objectAtIndex:indexPath.row] demIdImmeuble]];
		cell.lbl_demLot.text=[NSString stringWithFormat:@"%@", [[tab_Demandes objectAtIndex:indexPath.row] demIdLot]];
		cell.lbl_demDescriptif.text=[NSString stringWithFormat:@"%@", [[tab_Demandes objectAtIndex:indexPath.row] demTitle]];
		if ([[[tab_Demandes objectAtIndex:indexPath.row] demStatut] isEqualToString: @"Validée"])
		{
		cell.lbl_ImageView.image=[UIImage imageNamed:@"VDEM2.png"];
		}
		if([[[tab_Demandes objectAtIndex:indexPath.row] demStatut] isEqualToString: @"Initiée"])
		{
		   cell.lbl_ImageView.image=[UIImage imageNamed:@"IDEM.png"];
		}
		if([[[tab_Demandes objectAtIndex:indexPath.row] demStatut] isEqualToString: @"Terminée"])
		{
		cell.lbl_ImageView.image=[UIImage imageNamed:@"TDEM.png"];
		}
		if([[[tab_Demandes objectAtIndex:indexPath.row] demStatut] isEqualToString: @"En coursée"])
		{
		cell.lbl_ImageView.image=[UIImage imageNamed:@"EDEM.png"];
	 
		}
	
	return cell;
	   
}
```


----------



## Nyx0uf (24 Septembre 2010)

Et j'espère que tu fais pas un [demSelected release] quelque part.

Y a aucune raison que ce soit une ivar, dans ton didSelectRow: tu fais juste un :


```
Demande* demSelected = [tab objectAtIndex:indexPath.row];
```


----------



## ntx (24 Septembre 2010)

L'outil "Allocations" est bien pratique pour suivre les allocations/déallocation sur tes objets


----------



## BooBoo (25 Septembre 2010)

Tu fais quoi ensuite avec ton demSelected mis a jour dans le didSelect ?


----------



## tatouille (25 Septembre 2010)

shift-command-y je crois que tu dois avoir un stack t'indiquant sur quel symbol le bad-exec apparait et dans quel thread, bien sur parfois le stack est corrompu quand tu as une appli engageant plus de 15 threads avec des try catch partout dans le code, mais dans ton cas...

quand tu auras finalement appris a te servir de GDB integré a xcode, tu mettras un breakpoint au bon endroit et le probleme se reglera de lui meme, c'est comme le port-salut c'est ecrit dessus. et si tu penses qu'il y des exceptions throwed qui pourraient cacher le probleme active "breakpoint on throw ou catch".

+ "static NSString *CellIdentifier = @"Cell";" arrete de copier betement les exemples que tu trouves, le cellIdentifier doit etre Unique, j'ai deja mainte et mainte fois posé un commentaire a propos de cette crétinerie, si tu veux reordered delete...

de plus il te manque une classe ton data source qui controlle les valeurs donnees a la tableview (un object contenant un array pour les valeurs (un objet contenant une image des proprietes a passer a la cell view) et un array pour la description bien sur bindé 

le premier qui me dit "mais y a pas les bindings sur l'iphone je le tappe..."

et de cette classe, bien sur il est facile de  transmettre une representation a des objects "managés" ou meme une simple base sqlite ou des objets distants (sur un serveur)

la tu melanges la vue, le model, le controller plus dans ton cas le DataModel controller qui est absent 

mais j'en concois la difficulté la tableview est peut etre l'objet le plus mal fait de cocoa et uikit on peut sentir le repatch of repatch d'un design bancale des le depard, c'est pourquoi bon nombre de gens ont cree un tableview wrapper pouvant manipuler les sections aussi et en cocoa le multicolumn le tout accroché a un vraie datasource controller marquant par exemple des values deleted sans pour autant les virées du model original car tu auras peut etre besoin de faire des sync avec des objets (timestamp cree avec la meme base de reference est une bonne solution) distant que cela soit du network ou provenant d'une autre application

le wrapper ton je te parle represente 6 classes indestructicbles sans faiblesse qui t'assure un minimum de code au lieu du a la va comme je te pousse implementant les tableview delegates sur place creant un code illisible et incomprehensible heavy et finalement bugé et sale.

un conseil quand tu developpes pense "objet" et non pas le nez coincé dans l'application et ce qu'elle doit faire et finir avec une horreur lourde a changer et a faire evoluer avec un code non reutilisable, la mode des faux genies  Indiens de l'informatique est un peu passée... les gens ont ete brulés des entreprises en sont mortes..., la tu fais du _Bangalore_ style... du _Bollywood plein de couleur ca chante ecetera mais au final c'est pourave et ca a couté excessivement chers

_


----------



## Lio70 (26 Septembre 2010)

tatouille a dit:


> un conseil quand tu developpes pense "objet" et non pas le nez coincé dans l'application et ce qu'elle doit faire et finir avec une horreur lourde a changer et a faire evoluer avec un code non reutilisable, la mode des faux genies  Indiens de l'informatique est un peu passée... les gens ont ete brulés des entreprises en sont mortes..., la tu fais du _Bangalore_ style... du Bollywood plein de couleur ca chante ecetera mais au final c'est pourave et ca a couté excessivement cher


Niark 
C'est la valeur ajoutee des interventions de Tatouille,en plus du conseil dev pertinent. Ca detend. Je lirais ce forum rien que pour ca.


----------



## Nyx0uf (26 Septembre 2010)

C'est vrai qu'on imagine pas un post de tatouille sans comparaison cinglante 

Mais fait gaffe tatouille, les nioubs se vexent ! :rateau:


----------



## esbeone (27 Septembre 2010)

bonjour à tous,

bon il s'en est passé des trucs ce week end sur le thread ... je suis rhabillé pour l'hiver là ... 

Effectivement mon code n'est pas bien organisé,  même si ça n'excuse pas tout c'est ma 1ère app et je connais pas obj-C ni le C. Je veux dans un premier temps faire quelque chose de fonctionnel, histoire de prendre en main le dev Iphone,les Views et contrôles. 

Je suis là pour apprendre donc tous les conseils sont bons à prendre. Et c'est vrai je suis passé par des tutos sur le net, quand on connait rien bein c'est magnifique dans un premier temps ... 

J'utilise les breakpoints et les "try/catch" mais je n'arrive pas à debugger ce problème. Je connais pas bien les outils et l'environnemnt de dev.

NyxOuf et Booboo : j'utilise demSelected pour l'affichage dans deux autres vues.

Je vais tester vos conseils.  je reposterai si j'ose ... :affraid:  ... 

bonne journée et merci


----------



## esbeone (27 Septembre 2010)

Encore une fois désolé pour mon code pas organisé, mais je debute sur xcode seul donc bon ...  

Dans les autres vues j'utilise demSelected comme ça,pour l'affichage :


```
lbl_copro.text=demSelected.demIdCopro;
	lbl_immeuble.text=demSelected.demIdImmeuble;
	lbl_lot.text=demSelected.demIdLot;
	lbl_statut.text=demSelected.demStatut;
	txtview_descriptif.text=demSelected.demDescriptif;
	lbl_nom.text=demSelected.demAuteur;
	lbl_date.text=demSelected.demCreated;
	lbl_titre.text=demSelected.demTitle;
```

ntx je regarde dans l'outil allocations.

NyxOuf plusieurs fois tu m'as parlé du debugger, je regardais et encore maintenant mais c'est vraiment pas évident au premier abord.


EDIT:
Voici ce qu'il ya dans le debugger:

-[MyTableViewController requestReloadDone:]
CFArrayRemoveAllValues
_CFArrayRemoveAllValues
CFRelease
-[Demande dealloc]
obj_msgSend

C'est bien le dealloc des demandes qui plante, d'ailleurs quand je commente ces release dans le dealloc il n'y a plus de plantages mais des fuites (normal).

Je ne release les objets dem qu'après les avoir ajoutés au tableau, je ne fais pas d'autres release ailleurs. Si je vais sur une autre vue (pas en cliquant sur la tableView le problème persiste, cela ne vient pas de demSelected que j'utilise dans le didSelectRow.


----------



## esbeone (27 Septembre 2010)

bon et bien problème réglé 

le problème était qu'il y avait un temps de réponse que je ne voyais pas en mode debug, entre le moment où je fais ma requête et le moment où je recois le JSON. Forcément au "step by step" j'avais tout le temps du monde ... et le comportement n'était pas le même quen release. d'où le debug hasardeux. 

je vais m'attaquer à la réorganisation du code.

Merci à tous pour votre aide constructive, je poursuis mon chemin ... bonne continuation a vous

++


----------

