Détruire un objet

KassKass Membre
19:49 modifié dans API UIKit #1
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 !

Réponses

  • Philippe49Philippe49 Membre
    19:49 modifié #2
    dans 1235656728:

    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.

    [self.view setHidden:YES];
    [self release];

    Comment je pourrais détruire cette vue?


    Tout dépend du mode d'apparition de cette vue addSubview ? pushViewController ? presentModalViewController ...
  • KassKass Membre
    19:49 modifié #3
    elle a été ajouté avec addSubview.
    ce que je voudrais donc, c'est détruire mon instance du controlleur de la vue.
  • Philippe49Philippe49 Membre
    19:49 modifié #4
    Pour retirer la vue : [laVue removeFromSuperview];
    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.
  • KassKass Membre
    19:49 modifié #5
    dans mon cas l'IBAction du bouton, est une méthode du controleur qui doit être détruit
  • Philippe49Philippe49 Membre
    19:49 modifié #6
    Ce contrôleur à  détruire (B) a été lui-même créé par un  contrôleur (A)
    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.
  • KassKass Membre
    19:49 modifié #7
    ça serait efefctivement plus simple. Mais comment je peux faire pour que mon bouton présent dans mon Xib (B), ait accès a ma methode de destruction dans mon contrôleur (A)?
  • Philippe49Philippe49 Membre
    février 2009 modifié #8
    dans 1235682045:

    ça serait efefctivement plus simple. Mais comment je peux faire pour que mon bouton présent dans mon Xib (B), ait accès a ma methode de destruction dans mon contrôleur (A)?


    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 :)
  • KassKass Membre
    19:49 modifié #9
    Bon je comprend pas, ca fait plus de 2 heures que j'éssayes d'y faire marcher, mais sans succès.

    J'ai donc réalisé le bouton dans IB.
    Ensuite dans l'interface du controller B il y a ça:

    <br />IBOutlet UIButton *destroyButton;<br />@property (nonatomic, retain) UIButton *destroyButton;<br /><br />et aussi le @synthesize.<br />
    



    Ensuite dans mon controller A, juste après avoir créé mon instance du controller B j'ai bien écris:

    [monControllerB.destroyButton addTarget:self action:@selector(destroy:) forControlEvents: UIControlEventTouchUpInside];
    


    créé ma méthode destroy dans mon controller A:

    - (void)destroy:(id)sender
    


    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  ::)

  • Philippe49Philippe49 Membre
    février 2009 modifié #10
    Cela ressemble à  un message qui n'et pas envoyé au bon individu.
    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.
  • Philippe49Philippe49 Membre
    19:49 modifié #11
    Voici un modèle.
    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é.
  • KassKass Membre
    19:49 modifié #12
    Merci beaucoup pour ton aide très précieuse !

    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:
    [view removeFromSuperview];
    


    ç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?
  • Philippe49Philippe49 Membre
    février 2009 modifié #13
    dans 1235742607:


    Mon Controller B dispose d'un Timer, j'ai mis des NSLog afin de voir s'il tournait toujours, et oui.

    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


    dans 1235742607:

    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?

    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.
  • KassKass Membre
    19:49 modifié #14
    j'utilise déjà  un timer invalidate dès que mon Countdown arrive à  0. Mais dès que le timer est "invalidate", il va être recréé pour le niveau suivant (c'est un jeu sur 10 niveaux).

    donc à  chaques fois il est créé comme cela:

    countdown = [[NSTimer scheduledTimerWithTimeInterval:1.0&nbsp; target:self selector:@selector(updateCountdown:) userInfo:nil repeats:YES] retain];
    


    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 !  ::)
  • KassKass Membre
    19:49 modifié #15
    Bon j'arrive à  arrêter mon Timer grâce a une fonction destroy Timer présente dans mon Controller B.

    - (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 ...
  • Philippe49Philippe49 Membre
    19:49 modifié #16
    Il serait plus logique de faire
    - (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)
  • KassKass Membre
    19:49 modifié #17
    Je donnes de mes nouvelles que maintenant, car je travaille sur un projet java en parallèle.

    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:

    if (monControllerB)
    


    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  ???
  • Philippe49Philippe49 Membre
    mars 2009 modifié #18
    dans 1235852180:

    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:
    if (monControllerB)
    

    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).

    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; 

    dans 1235852180:

    J'ai deux petites questions:
    - alloc et retain c'est la même chose?

    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.


    dans 1235852180:

    - comment peut on voir dans le debugger, si un variable a bien été dealloc?

    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.

Connectez-vous ou Inscrivez-vous pour répondre.