Problem der Aufhebung von NSTimer in dealloc
Folgendes ist mein code:
.h-Datei:
#import "Foundation/Foundation.h"
@interface GObject:NSObject{
NSTimer* m_Timer;
}
@property(nonatomic, retain) NSTimer* m_Timer;
- (void)Initialize;
- (void)TimerCallback:(NSTimer*)pTimer;
@end
.m-Datei:
@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
Nun, wenn die dealloc aufgerufen wird, stürzt das Programm ab in die Zeile ungültig zu machen, den timer. Die nächsten zwei Zeilen nicht einmal aufgerufen. Ich bekomme eine Fehlermeldung "EXC_BAD_ACCESS". Kann mir jemand sagen, warum das passiert, und was ist der richtige Weg, zu stoppen und loslassen ein NSTimer member-variable in einer Klasse.
- Erstellen Sie die getter/setter der property mit @synthetisieren?
- Ja, ich brauche den Zugriff auf diese timer von außerhalb meiner Klasse auch. Obwohl setter ist nicht erforderlich.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Habe ich einige der Forschung und tests, und konnte herausfinden, die Antwort auf meine eigene Frage. Ok, hier geht es:
Wann immer wir weisen
self
als Ziel derNSTimer
ist, wird der timer enthält einen Verweis auf unser Objekt. Wenn der timer zu wiederholen (oder einen längeren Zeitraum), es wäre nicht ungültig, die auf Ihrer eigenen (oder zu lang dauert, erlöschen automatisch, wenn nicht wiederholt). Also, auch wenn das Objekt freigegeben wird, in der Zwischenzeit, es würde nicht nennen diedealloc
Methode, wie die retain-count wäre zumindest 1. Nun, ich wurde zwangsweise versucht, dellocate mein Objekt durch Aufruf wiederholt releases auf, bis der retain count 0 wurde. Das war mein Fehler.Aber wenn Sie nicht tun,, Ihr Objekt lebendig zu halten, und Sie werden schließlich einen memory-leak, da verliert man den rest der Referenzen auf das Objekt von verschiedenen Versionen. Die einzige, die gehalten werden, mit der
NSTimer
. Das klingt wie eine deadlock-situation. Mein code abgestürzt, weil, wenn diedelloc
versucht zu entkräften, dieNSTimer
, versuchte es zu release der Hinweis, dass es hielt. Aber seit ich war ein Klugscheißer und verringert den retain-count auf 0 schon, dazu führen würde, dass eine memory-exception.Um dieses Problem zu lösen, Erstens, ich räumte meine Tat und entfernt den code gewaltsam dellocate das Objekt. Dann, kurz bevor ich wollte, dass das Objekt dellocated, rief ich den NSTimer ist ungültig Funktion. Dieser veröffentlicht die Ziel-Instanz, dass der Timer hatte. Danach ruft
release
auf mein Objekt erfolgreich dellocated es.In der unteren Zeile ist, wenn das Objekt NSTimers, die sich wiederholen oder die nicht ungültig (bekommen mehr) automatisch, nie erlöschen Sie in der delloc-Funktion. Der delloc nicht aufgerufen werden, bis der timer hält die Instanz an Ihrem Objekt. Stattdessen eine cleanup-Funktion, um die Unwirksamkeit der Timer, bevor die Freigabe des Objekts. Das ist die Lösung, die ich kam mit. Wenn es eine bessere gibt, die ich am meisten sicherlich wissen wollen.
Gibt es ein paar Dinge, die Sie angehen sollten, um hier wieder Ordnung zu schaffen.
Deine Klasse Erklärung ein wenig aus. Wenn Sie wollen, um zu Erben von NSObject, die korrekte syntax ist:
In Ihrer Umsetzung, Sie implementieren sollten
- (id)init
eher als- (void)Initialize
. Es gibt keine Instanz-Methode- (void)Initialize
... es ist eine statische Methode+ (void)initialize
. Hinweis: die+
und der Unterschied in der groß - /Kleinschreibung, die ist bedeutend): dieinitialize
Methode wird aufgerufen, sobald in Ihrem Programm vor der Klasse erhält seine erste Methode.In diesem Fall, Ihre
Initialize
Methode nicht aufgerufen wird (und es geschrieben ist falsch, und es ist eine Instanz-Methode anstelle einer statischen Methode). Statt, die Sie umsetzen wolleninit
, die den designierten Initialisierer für NSObject Instanzen:Schließlich, sicher sein, verwenden Sie die
@
- symbol vor den property-Anweisung:Und vergessen Sie nicht, zu synthetisieren, die es in Ihrer Umsetzung:
-Initialize
- Methode niemals aufgerufen wird, und somit nie schafft den timer. Dann ist dein dealloc-Methode aufrufen release auf einen Zeiger als war nie initialisiert, dieser Zeiger werden konnte, deutete auf irgendwelche random-Objekts in das Programm, oder auch nur Müll.gut, muss ich sagen, dass Sie können finden Sie unter apple-Entwickler für die Dokumentation, wie Apple ' s Klasse Referenz. Sie können von dort aus sehen, dass wenn ungültig: Methode wird aufgerufen, wird die timer-Version: Methode wird aufgerufen, bevor ungültig: Methode gibt.
Ich habe das gleiche Problem mit dem Speicherverlust durch wiederholte NSTimer auf einer der view-controller. Dieser view-controller wird nicht veröffentlicht, wenn es sollte. Ich endlich dieses Problem gelöst, indem mein timer auf die Haupt-Anwendung delegieren code, wo es keine Notwendigkeit, lassen Sie die timer.
Andere Lösung wäre, ein eigenes Objekt erstellen, das sich mit der
NSTimer
callback (einigeTimerController
). Das Objekt, falls erforderlich, kann die Methoden aufrufen, die auf Ihremself
controller.Nun der timer nicht, behalten Sie einen Verweis auf
self
und wennself
wird freigegeben- dealloc
genannt werden sollte, und Sie für ungültig erklären kann, und setzen auf nil dieTimerController
und der timer selbst.