2010-06-23 8 views
3

J'ai une situation où parfois ma méthode -tableView: numberOfRowsInSection: demande le compte d'un NSArray désalloué. J'aimerais pouvoir tester si ce tableau est désalloué d'une manière sûre et ne fait pas appel à un zombie.Test si un objet a été désalloué

Mon code ressemble actuellement:

-(NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section 
{ 
    if (! self.offers){ 
     return 0; 
    } 
    return [self.offers count]; 
} 

Je viens débogueur franchissait ce qu'il a observé et passer le test ! self.offers puis écraser brutalement sur [self.offers count]. Je NSZombies sous tension, et à cette ligne je reçois le message NSLog:

-[__NSArrayM count]: message sent to deallocated instance 0x283dc0 

Alors quel que soit self.offers est, à ce stade, n'est pas nul, mais aussi à ne pas être pointés quoi que ce soit valide. Comment puis-je tester pour cela?

EDIT: Merci pour le dur-amour, amis. J'ai compris pourquoi j'ai eu des problèmes avec ma gestion de la mémoire - c'est en fait une question de relations de délégués qui traînent plus longtemps qu'elles ne sont utiles. Voir ici pour la réponse complète à mon problème: Managing calls to objects that get deallocated when the view is backed out of

+0

double possible de [Comment déterminer si j'ai un pointeur vers l'objet libéré?] (Http://stackoverflow.com/questions/12280799/how-to-determine- if-i-have-a-pointer-to-released-object) – OrangeDog

Répondre

15

Il n'est pas possible de "tester" pour ceci - une fois qu'un objet est libéré, il est parti, et le pointeur vers lui est effectivement garbage. Faire quoi que ce soit avec elle est susceptible de s'écraser.

Désolé d'être le porteur de mauvaises nouvelles, mais la seule façon de faire fonctionner cela est de s'assurer que la gestion de la mémoire autour (dans ce cas) offers est correcte à tous les usages-- conserver et libérer correctement du tout les points où cette variable d'instance est manipulée, et ce ne sera jamais une poubelle non nulle. Vous devriez essayer d'exécuter l'analyseur statique (Construire-> Construire et Analyser) pour commencer - cet outil peut aider à marquer les problèmes de gestion de la mémoire mémoire sans beaucoup de fouille supplémentaire de votre part.

+2

+1 et définissez 'offres' à' nil' une fois que vous en aurez abandonné la propriété. De cette façon vous pouvez changer votre code en 'return [self.offers count];', puisque '[nil count]' renvoie 0. :) –

1

Vous devriez éviter le problème en corrigeant le code afin qu'il ne libère pas le tableau lorsque vous en avez toujours besoin.

0

Cela pourrait ne pas être pertinent à votre question (test si elle est désaffectée) - mais il semble que votre offre gamme a la même ou une plus longue vie que votre UITableViewController, êtes-vous certain que vous retenez ce tableau ou que vous ne le libère pas accidentellement ailleurs. Je suis d'accord avec ce quixoto a dit ci-dessus

0

Une autre chose que vous devez vous demander est: mon application a-t-elle été conçue correctement? Une tableview repose sur une source de données pour la peupler (ce qui dans votre cas est le tableau offers), donc si vous le libérez quelque part dans le code, vous devez revenir en arrière et repenser votre conception. Si vous tentez de déterminer s'il est désaffecté parce que vous essayez de le réparer à partir d'un problème précédent, il peut être utile de regarder dans votre code pour voir où il est conservé/libéré.

0

Oui, une fois qu'un objet est désalloué, il est parti, et le pointeur vers lui est effectivement garbage. Faire quoi que ce soit avec elle est susceptible de s'écraser.

Cependant, il est POSSIBLE de tester. Il existe une solution de contournement pour cela. (Bien que les solutions de contournement ne se substituent pas aux bonnes pratiques de conception!): Vous avez une variable BOOL globale, que vous définissez sur l'allocation.Voici un exemple d'utilisation pour vérifier si un AVAudioPlayer est en train de jouer. Si elle était en cours de lecture et que la vue était fermée, l'application se bloquait. Arrêter simplement la musique n'était pas une option à cause des threads d'arrière-plan, etc. Mais appeler [newPlayer isPlaying] se bloque quand newPlayer est déjà sorti! Donc, une solution de contournement de drapeau BOOL a fait fonctionner. (Les commentaires de bonnes pratiques de conception sur ce serait utile.)

// In implementation 
static AVAudioPlayer *newPlayer; 
static BOOL hasMusicFinishedPlaying; 

// When Playing the music, set flag 
    newPlayer =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: soundPath] error:nil];  
    hasMusicFinishedPlaying = NO; 

// Callback method to release new player in playKeySound 
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)newPlayer successfully:(BOOL)flag { 

    [newPlayer release]; 
    hasMusicFinishedPlaying = YES; 
} 

// On going back to another page. We don't want to keep ViewController in stack. 

    if (!hasMusicFinishedPlaying){ 
     return; 
    } 

    [self.navigationController popViewControllerAnimated:YES]; 
1

Vous pouvez ajouter

-(void)dealloc { ... } 

Et laisser vide si c'est le droit de le faire, et ajoutez point d'arrêt en elle.

Cette réponse correcte à ARC et NON-ARC

+1

'dealloc' ne peut pas être vide en non-arc. Vous * devez * avoir '[super dealloc]' comme dernière ligne de cette méthode. –

Questions connexes