Question

Ce qui suit est mon code:

.h:

#import "Foundation/Foundation.h"
@interface GObject:NSObject{
    NSTimer* m_Timer;
}
@property(nonatomic, retain) NSTimer* m_Timer;

- (void)Initialize;
- (void)TimerCallback:(NSTimer*)pTimer;
@end

fichier .m:

@implementation GObject

@synthesize m_Timer

- (void) Initialize{
    self.m_Timer = [NSTimer scheduledTimerWithTimeInterval:5.0 
                       target:self 
                       selector: @selector(TimerCallback:) 
                       userInfo: nil 
                       repeats: YES];

}

- (void)TimerCallback:(NSTimer*)pTimer {
    //Some Code
}
- (void)dealloc {
    [m_Timer invalidate]; //--Crashes Here
    [m_Timer release];
    m_Timer = nil;
    [super dealloc];
}
@end

Maintenant, quand le dealloc est appelé, le programme se bloque dans la ligne invalidant la minuterie. Les deux lignes suivantes ne sont même pas appelé. Je reçois une erreur « EXC_BAD_ACCESS ». Quelqu'un peut-il me dire pourquoi cela pourrait se produire, et quelle est la bonne façon d'arrêter et de libérer une variable membre NSTimer dans une classe.

Était-ce utile?

La solution

Je l'ai fait des recherches et des tests, et pourrait comprendre la réponse à ma propre question. Ok, voilà:

Chaque fois que nous attribuons self comme cible au NSTimer, la minuterie contient une référence à notre objet. Si la minuterie répète (ou a une longue période de temps), il ne s'invalidées sur son propre (ou prendra trop de temps pour invalider automatiquement, sinon répéter). Ainsi, même si l'objet est libéré dans l'intervalle, il ne serait pas appeler la méthode dealloc, comme conserver le nombre serait au moins 1. Maintenant, je tentais de force à dellocate mon objet en appelant versions répétées sur elle jusqu'à la conserver Ce nombre est devenu 0. était mon erreur.

Mais si vous ne le faites pas, votre objet gardera en vie, et vous finirez par avoir une fuite de mémoire que vous perdez le reste des références à cet objet par différentes versions. Le seul sera conservé avec le NSTimer. Cela ressemble à une situation de blocage. Mon code est écrasé, parce que quand la delloc a tenté d'invalider le NSTimer, il a essayé de libérer la référence qu'il détenait. Mais depuis que j'avais été réduit et smartass le compte conserver à 0 déjà, qui provoquerait une exception mémoire.

Pour résoudre ce problème, tout d'abord je nettoyais mon acte et a retiré le code pour dellocate force l'objet. Ensuite, juste avant que je voulais l'objet à dellocated, j'ai appelé fonction invalidate du NSTimer. Cette libéré l'instance cible que la minuterie a. Après cela, appelant release sur mon objet dellocated avec succès.

La ligne de fond est, si votre objet a NSTimers qui se répètent ou ne rend pas nulle (obtenir plus) automatiquement, ne les invalide dans la fonction delloc. Le delloc ne sera pas appelé jusqu'à ce que la minuterie tient l'instance à votre objet. ont plutôt une fonction de nettoyage pour invalider les minuteries, avant de libérer l'objet. Telle est la solution que je suis venu avec. S'il y a un meilleur là-bas, je veux certainement savoir.

Autres conseils

Il y a quelques choses que vous devez faire face à nettoyer cela.

Votre déclaration de classe est un peu hors. Si vous voulez hériter de NSObject, la syntaxe correcte est:

@interface GObject : NSObject

Dans votre implémentation, vous devez mettre en œuvre - (id)init plutôt que - (void)Initialize. Il n'y a pas de méthode d'instance - (void)Initialize ... il y a une + (void)initialize méthode statique. Notez la + et la différence de capitalisation, ce qui est significatif):. La méthode initialize est appelée une fois dans votre programme avant la classe reçoit sa première méthode

Dans ce cas, votre méthode de Initialize n'est pas appelé du tout (il est mal orthographié, et il est une méthode d'instance au lieu d'une méthode statique). , Vous voulez plutôt que de mettre en œuvre init, qui est l'initialiseur désigné pour les instances NSObject:

- (id)init {
    if (self = [super init]) {
        self.m_Timer = [NSTimer scheduledTimerWithTimeInterval:5.0 
                   target:self 
                   selector: @selector(TimerCallback:) 
                   userInfo: nil 
                   repeats: YES];
    }
    return self;
}

Enfin, assurez-vous d'utiliser le symbole de @ avant la déclaration de propriété:

@property(nonatomic, retain) NSTimer* m_Timer;

Et ne pas oublier de les synthétiser dans votre implémentation:

@implementation GObject

@synthesize m_Timer;

Eh bien, je dois dire que vous pouvez vous référer à la documentation développeur Apple, comme la référence de classe d'Apple. Vous pouvez voir à partir de là que lorsque invalidate: méthode est appelée, la libération de la minuterie: méthode sera appelée avant invalidate:. Méthode renvoie

J'ai le même problème de fuite de mémoire à l'aide NSTimer répétée sur l'un des contrôleur de vue. Ce contrôleur de vue ne sera pas libéré quand il le devrait. J'ai finalement résolu ce problème en déplaçant mon minuteur le code principal délégué d'application où il n'y a pas besoin de libérer la minuterie.

Une autre solution serait de créer un objet distinct qui traite le rappel de NSTimer (certains TimerController). Cet objet, le cas échéant, peut appeler les méthodes sur votre contrôleur self.

Maintenant, la minuterie ne conservera pas une référence à self et quand self sera désallouée, - dealloc doit être appelé et vous pouvez annuler et mettre à zéro la TimerController et la minuterie elle-même.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top