Détruire un objet
Bonjour à tous,
Je suis entrain de un petit programme. J'ai une vue avec une liste de pays, et lorsque je clique sur un d'entre eux, une nouvelle vue s'ouvre avec les détails du pays. J'ai créé un bouton qui me permet de quitter cette vue.
Je sais que c'est certainement pas très juste de faire comme ça mais j'ai donc dans la méthode appellé par le bouton:
[self.view setHidden:YES];
[self release];
mais bon bien sûr ça ne marche pas. Comment je pourrais détruire cette vue?
Avec les informations qui s'affiche dans ma console, je vois bien que la vue continue de tourner en fond.
Merci de votre aide !
Je suis entrain de un petit programme. J'ai une vue avec une liste de pays, et lorsque je clique sur un d'entre eux, une nouvelle vue s'ouvre avec les détails du pays. J'ai créé un bouton qui me permet de quitter cette vue.
Je sais que c'est certainement pas très juste de faire comme ça mais j'ai donc dans la méthode appellé par le bouton:
[self.view setHidden:YES];
[self release];
mais bon bien sûr ça ne marche pas. Comment je pourrais détruire cette vue?
Avec les informations qui s'affiche dans ma console, je vois bien que la vue continue de tourner en fond.
Merci de votre aide !
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Tout dépend du mode d'apparition de cette vue addSubview ? pushViewController ? presentModalViewController ...
ce que je voudrais donc, c'est détruire mon instance du controlleur de la vue.
Pour détruire le contrôleur, il faut savoir si l'IBAction du bouton est une méthode de ce contrôleur, ou du contrôleur de la superview.
Ce serait plus simple/logique que l'IBAction de destruction soit une méthode de A, ce dernier possédant une variable d'instance pointant sur B.
Tu fais la connection par code lors de la création du controller B par A et non dans IB
[controllerB.destroyButton addTarget:self action:@selector(destroy) forControlEvents: UIControlEventTouchUpInside]
[EDIT] @selector( destroy :)
J'ai donc réalisé le bouton dans IB.
Ensuite dans l'interface du controller B il y a ça:
Ensuite dans mon controller A, juste après avoir créé mon instance du controller B j'ai bien écris:
créé ma méthode destroy dans mon controller A:
J'ai juste mis un NSLog dedans, afin de vois si la méthose est bien appellée.
Mais malheureusement ça ne marche pas. J'ai essayé en modifiant plein de choses, et toujours bien. Ai-je utilisé la bonne méthode pour crééer mon bouton? C'est bon si je l'ai créé dans IB puis relié à un IBOutlet?
Merci ::)
Tu n'aurais pas mis un controller B dans le nib associé à A + créer un controller B dans une méthode par un alloc-init ?
cela ferait deux instances d'un tel contrôleur, et le bouton ayant reçu le message ne serait pas le bon.
Peut-être ne fais-tu pas le addSubview avant de paramétrer l'action du bouton.
Il faut comprendre que le fonctionnement est "paresseux", donc si il n'y a pas de addSubview le désarchivage du nib peut-être retardé.
Maintenant ma méthode destroy est apellée, le problème, est que je réalisais le addSubView à la fin.
Le problème maintenant est ma méthode destroy:
j'ai mis un:
ça marche très bien, mais ensuite comment je détruit mon Controller? J'ai essayé avec un simple release, mais je vois qu'il tourne toujours en fond.
Mon Controller B dispose d'un Timer, j'ai mis des NSLog afin de voir s'il tournait toujours, et oui.
D'ailleurs petite question au passage. Qu'elle est la grosse différence entre un release et un dealloc? et a quel moment vont ils être apellés?
Le release sert je crois à libérer la mémoire, mais comment ça se fait que mon controller existe alors toujours? Comment le détruire complètement, afin que dans mon controlleur A l'on puisse sélectionner un autre pays, qui va initialiser un nouveau Controller B?
Cela doit être lié au fait qu'un timer retient sa target.
Il y a un post assez récent sur ce sujet. Voir si un [timer invalidate] est suffisant
Le retain ajoute 1 au compteur de références (=nombre de retain reçus)
Le release retire 1 au compteur de références (=nombre de retain reçus)
dealloc est automatiquement appelé sur un objet lorsque son compteur de références passe à la valeur 0.
donc à chaques fois il est créé comme cela:
Parcontre dès que je supprime le retain, un EXC_BAD_ACCESS est affiché.
Mon invalidate est réalisé dès que le countdown a atteint 0. J'effectue juste après un [monTimer release];
le timer se recréé bien losque la boucle recommence. C'est pour ça lorsque j'apelle la fonction destroy je vois que mon Timer continue.
J'ai essayé de mettre un [monTimer invalidate] dans le dealloc de mon COntroller B, mais ça plante le programme.
Donc il faut que j'arrive a arrêter mon countDown.
Je vais essayer celà , et je donnerais des nouvelles ! ::)
- (void)destroyCountdown
{
[countdown invalidate];
[countdown release];
}
ensuite dans mon controlleur A j'ai:
- (void)destroy:(id)sender
{
[monControllerB destroyCountdown];
[monControllerB release];
[monControllerB.view removeFromSuperview];
}
mais j'ai l'impression que mon controlleur éxiste toujours. Car lorsque je clique sur le même pays, une nouvelle instance se lance, puis le message EXC_BAD_ACCESS s'affiche ...
- (void)destroy:(id)sender
{
[monControllerB destroyCountdown];
[monControllerB.view removeFromSuperview];
[monControllerB release];
}
Quand à l'erreur EXC_BAD_ACCESS , cela concerne typiquement un message envoyé à un objet désalloué. Donc tu es sur la bonne voie : en gros, tu as mis le retainCount à 0 pour un objet et tu lui envoies de nouveau un release. ce n'est sans doute plus qu'une question de petit réglage et d'ordonnancement des derniers "release" . Peut-être est-ce tout simplement l'inversion ci-dessus (libérer la view avant de libérer son controller)
J'avais déjà essayé le mettre le release après le remove, mais ça ne change pas grand chose.
Dans mon controller B, j'ai regardé partout si j'avais pas oublié un release pour une quelconque variable, mais tout à l'air ok.
dans ma methode destroy, a mon avis le release marche.
Mais lorsque l'on click sur un autre pays dans la liste de mon Controller A, j'ai fais un:
afin de vérifier s'il est vide ou pas. Mais le NSLog qui est dedans s'affiche toujours, (sauf bien sûr la première fois).
Quand je regarde ensuite le debugger, quand le programme plante il m'affiche une ligne d'un [NSNumber alloc]. Pourtant j'ai bien un release pour cette variable après.
J'ai deux petites questions:
- alloc et retain c'est la même chose?
- comment peut on voir dans le debugger, si un variable a bien été dealloc?
J'espère avoir été un petit peu clair ???
Le simple release suivi de dealloc n'empêche pas la variable automatique monControllerB de pointer sur la zone mémoire précédente. Ainsi, monControllerB != nil et le test if(monControllerB) passe dans la branche positive. Par contre, si tu appliquais une méthode if( [monControllerB class]==[BViewController class]), demandant ainsi d'interpréter la zone mémoire pointée, là tu pourrais tester si cette zone est bien considérée comme désallouée.
Solution :
1) Si tu veux revenir à l'état initial pour utiliser un test if(monControllerB), il faut mettre aussi monControllerB=nil.
2) Si monControllerB est une property en mode retain, tu peux faire le release et la mise à nil en une seule fois :Â self.monControllerB=nil;Â
alloc met effectivement le compteur de référence de 1. Mais il fait d'autre chose : alloue la mémoire avec mise à zéro , renseigne le champ isa (la classe de l'objet) , ...
Les méthodes d'initialisations init... laissent ce compteur à 1.
retain se contente d'incrémenter le compteur de références.
Je n'ai jamais vu de réponse à cette question, et je pense qu'il n'y en a pas.
Par contre, on peut laisser un NSLog dans le dealloc pour être averti.