NSTimer stoppt nicht nach [timer invalidate]

  • NSTimer stoppt nicht nach [timer invalidate]

    Na toll, jetzt hab ich auch noch ein Timer problem...
    Der Timer stoppt nicht und ich weiss net warum.

    datei.h:

    Quellcode

    1. #import <Cocoa/Cocoa.h>
    2. @interface start : NSObject {
    3. IBOutlet NSTimer *timer;
    4. }
    5. - (IBAction)befehl:(id)sender;
    6. @end

    datei.m:

    Brainfuck-Quellcode

    1. #import "start.h"
    2. @implementation start
    3. - (void)blabla {
    4. [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timerFired) userInfo:nil repeats:YES];
    5. }
    6. - (void)timerFired {
    7. [........];
    8. }
    9. - (IBAction)befehl:(id)sender {
    10. [timer invalidate];
    11. }
    12. @end
    Alles anzeigen

    Jemand ne Idee? ?(
  • macmoonshine schrieb:

    Ja, Du solltest den Timer auch zuweisen:

    Quellcode

    1. timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timerFired) userInfo:nil repeats:YES];


    Klappt ehrlich gesagt nicht. Danach kommt bei

    Quellcode

    1. - (IBAction)befehl:(id)sender {
    2. [timer invalidate];
    3. }

    logischerweise 'timer' undeclared (first use in this function)
  • Du erzeugst timer als auto-released instance [ NSTimer timerWith...] und das hinterlässt Dir einen verwaisten pointer (die Instanz wird vom Autorelease Pool freigegeben bevor Du in -befehl: wieder darauf zugreifst.
    Besagte timer-Instanz benötigt noch ein retain - am besten setzt Du das so um:

    Quellcode

    1. @interface start : NSObject {
    2. NSTimer *timer;
    3. }
    4. @property (retain) NSTimer *timer;
    5. @end

    Quellcode

    1. @implementation start
    2. @synthesize timer;
    3. - (void)blabla {
    4. self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timerFired) userInfo:nil repeats:YES];
    5. }
    6. -(void)dealloc
    7. {
    8. self.timer = nil;
    9. [ super dealloc];
    10. }
    Alles anzeigen

    Aber das sind alles Basics die Du eigentlich beherrschen solltest, bevor Du mit Timern rumspielst...(Speicherverwaltung, Namenskonventionen...)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Markus Müller ()

  • Markus Müller schrieb:

    Du erzeugst timer als auto-released instance [ NSTimer timerWith...] und das hinterlässt Dir einen verwaisten pointer (die Instanz wird vom Autorelease Pool freigegeben bevor Du in -befehl: wieder darauf zugreifst.

    Normalerweise ja, aber in diesem Fall: nein. Der durch -scheduledTimerWith... erzeugte Timer ist zwar entsprechend der Convenience-Allocator-Konvention autoreleased, er wird aber durch die NSRunLoop retained, in der er läuft. Mit anderen Worten: Auch ohne retain bleibt er bestehen, bis er invalidiert wird. Ob es guter Stil ist, ihn nicht selbst zu retainen, ist eine andere Frage. Aber das Problem mit dem Absturz dürfte eine andere Ursache haben. Der Debugger ist Dein Freund.
    Multigrad - 360°-Produktfotografie für den Mac
  • mattik schrieb:

    Markus Müller schrieb:

    Du erzeugst timer als auto-released instance [ NSTimer timerWith...] und das hinterlässt Dir einen verwaisten pointer (die Instanz wird vom Autorelease Pool freigegeben bevor Du in -befehl: wieder darauf zugreifst.

    Normalerweise ja, aber in diesem Fall: nein. Der durch -scheduledTimerWith... erzeugte Timer ist zwar entsprechend der Convenience-Allocator-Konvention autoreleased, er wird aber durch die NSRunLoop retained, in der er läuft. Mit anderen Worten: Auch ohne retain bleibt er bestehen, bis er invalidiert wird. Ob es guter Stil ist, ihn nicht selbst zu retainen, ist eine andere Frage. Aber das Problem mit dem Absturz dürfte eine andere Ursache haben. Der Debugger ist Dein Freund.

    Sicher?

    IIRC bleibt nur der Timer im System bestehen, nicht aber die Wrapperinstanz der Cocoa-Klasse NSTimer.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    mattik schrieb:

    Markus Müller schrieb:

    Du erzeugst timer als auto-released instance [ NSTimer timerWith...] und das hinterlässt Dir einen verwaisten pointer (die Instanz wird vom Autorelease Pool freigegeben bevor Du in -befehl: wieder darauf zugreifst.

    Normalerweise ja, aber in diesem Fall: nein. Der durch -scheduledTimerWith... erzeugte Timer ist zwar entsprechend der Convenience-Allocator-Konvention autoreleased, er wird aber durch die NSRunLoop retained, in der er läuft. Mit anderen Worten: Auch ohne retain bleibt er bestehen, bis er invalidiert wird. Ob es guter Stil ist, ihn nicht selbst zu retainen, ist eine andere Frage. Aber das Problem mit dem Absturz dürfte eine andere Ursache haben. Der Debugger ist Dein Freund.

    Sicher?

    IIRC bleibt nur der Timer im System bestehen, nicht aber die Wrapperinstanz der Cocoa-Klasse NSTimer.

    Die Doku spricht:

    Doku zu NSTimer schrieb:

    Note in particular that run loops retain their timers, so you can release a timer after you have added it to a run loop.
    Nach ersten Versuchen am lebenden Objekt kann ich das nur bestätigen ;)
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:

    Amin Negm-Awad schrieb:

    mattik schrieb:

    Markus Müller schrieb:

    Du erzeugst timer als auto-released instance [ NSTimer timerWith...] und das hinterlässt Dir einen verwaisten pointer (die Instanz wird vom Autorelease Pool freigegeben bevor Du in -befehl: wieder darauf zugreifst.

    Normalerweise ja, aber in diesem Fall: nein. Der durch -scheduledTimerWith... erzeugte Timer ist zwar entsprechend der Convenience-Allocator-Konvention autoreleased, er wird aber durch die NSRunLoop retained, in der er läuft. Mit anderen Worten: Auch ohne retain bleibt er bestehen, bis er invalidiert wird. Ob es guter Stil ist, ihn nicht selbst zu retainen, ist eine andere Frage. Aber das Problem mit dem Absturz dürfte eine andere Ursache haben. Der Debugger ist Dein Freund.

    Sicher?

    IIRC bleibt nur der Timer im System bestehen, nicht aber die Wrapperinstanz der Cocoa-Klasse NSTimer.

    Die Doku spricht:

    Doku zu NSTimer schrieb:

    Note in particular that run loops retain their timers, so you can release a timer after you have added it to a run loop.
    Nach ersten Versuchen am lebenden Objekt kann ich das nur bestätigen ;)

    Scherzkeks, das kenne ich.

    Ich habe das aber immer so verstanden, dass sie ihren internen Timer ein retain schickt, nicht der Instanz von NSTimer. Deshalb hatte ich das ja unterschieden. Das hat Auswirkungen für einen One-Shot-Timer, den ich deshalb immer gleich wegwerfe (ARP).

    Wenn ich aber einen wiederholten Timer hatte, hatte ich auch schon Probleme. Mag natürlich noch ein anderer Bug gewesen sein.

    +++

    Zur Überprüfung könnte man den Tiumer mal der RL explizit hinzufügen und den RC betrachten.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    Scherzkeks, das kenne ich.
    Isch bin halt eine rheinische Frohnatur.

    Amin Negm-Awad schrieb:

    Ich habe das aber immer so verstanden, dass sie ihren internen Timer ein retain schickt, nicht der Instanz von NSTimer.
    Davon steht Nichts in der Doku. Es wird immer vom Timer gesprochen. Wenn Du auf Deinen ketzerischen Thesen bestehst und nicht widerrufts, schlage ich als Kompromiss eine Exkomunnikation, Kirchenspaltung und paar Jahrhunderte Religionskriege vor.

    Amin Negm-Awad schrieb:

    Wenn ich aber einen wiederholten Timer hatte, hatte ich auch schon Probleme. Mag natürlich noch ein anderer Bug gewesen sein.
    Verstösst das nicht gegen das Prinzip (EDIT: 'Tschuldigung: Dogma, ich meinte natürlich Dogma) der Unfehlbarkeit?

    Amin Negm-Awad schrieb:

    Zur Überprüfung könnte man den Tiumer mal der RL explizit hinzufügen und den RC betrachten.
    So jetzt kommt der ernste Teil dieses Beitrags: Ich habe bei meinem Versuch eine Retained-Property auf Assign umgestellt und es gibt keinen Ärger, wenn der Timer abgeschossen wird. Und das funktionierte sogar wiederholt. Reicht das als Begründung?
    „Meine Komplikation hatte eine Komplikation.“
  • Amin Negm-Awad schrieb:



    Ich habe das aber immer so verstanden, dass sie ihren internen Timer ein retain schickt, nicht der Instanz von NSTimer. Deshalb hatte ich das ja unterschieden. Das hat Auswirkungen für einen One-Shot-Timer, den ich deshalb immer gleich wegwerfe (ARP).

    Wenn ich aber einen wiederholten Timer hatte, hatte ich auch schon Probleme. Mag natürlich noch ein anderer Bug gewesen sein.

    Zur Überprüfung könnte man den Tiumer mal der RL explizit hinzufügen und den RC betrachten.


    Die NSRunLoop retained den NSTimer. Sicher. Schon alleine, um in der timerFired-Methode eine gültige Referenz auf den Timer selbst liefern zu können.

    Ich habe eben mal getestet:

    Quellcode

    1. NSTimer* timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerFired:) userInfo:nil repeats:NO];
    2. NSLog(@"retain count before: %i",[timer retainCount]);
    3. [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    4. NSLog(@"retain count after: %i",[timer retainCount]);


    liefert


    2010-07-01 13:33:14.618 TimerTest[7005:a0f] retain count before: 1
    2010-07-01 13:33:14.622 TimerTest[7005:a0f] retain count after: 2
    Multigrad - 360°-Produktfotografie für den Mac
  • macmoonshine schrieb:

    Amin Negm-Awad schrieb:

    Scherzkeks, das kenne ich.
    Isch bin halt eine rheinische Frohnatur.

    Amin Negm-Awad schrieb:

    Ich habe das aber immer so verstanden, dass sie ihren internen Timer ein retain schickt, nicht der Instanz von NSTimer.
    Davon steht Nichts in der Doku. Es wird immer vom Timer gesprochen. Wenn Du auf Deinen ketzerischen Thesen bestehst und nicht widerrufts, schlage ich als Kompromiss eine Exkomunnikation, Kirchenspaltung und paar Jahrhunderte Religionskriege vor.

    Amin Negm-Awad schrieb:

    Wenn ich aber einen wiederholten Timer hatte, hatte ich auch schon Probleme. Mag natürlich noch ein anderer Bug gewesen sein.
    Verstösst das nicht gegen das Prinzip (EDIT: 'Tschuldigung: Dogma, ich meinte natürlich Dogma) der Unfehlbarkeit?

    Amin Negm-Awad schrieb:

    Zur Überprüfung könnte man den Tiumer mal der RL explizit hinzufügen und den RC betrachten.
    So jetzt kommt der ernste Teil dieses Beitrags: Ich habe bei meinem Versuch eine Retained-Property auf Assign umgestellt und es gibt keinen Ärger, wenn der Timer abgeschossen wird. Und das funktionierte sogar wiederholt. Reicht das als Begründung?


    Na, ja, in der Doku steht "Timer". Das muss eben nicht NSTimer heißen. Es ist ganz gewiss so, dass NSTimer ein Wrapper ist, es also noch einen Timer im System gibt. Anders etwa als bei NSView, den es im System nicht geben dürfte. (Jedenfalls sehe ich dort keine Notwendigkeit.)

    Als Beweis reicht mir der RC von mattik. Einfach mal einen Dangling-Pointer zu erzeugen, reicht ganz gewiss nicht. Wieso sollte der Speicherplatz belegt werden?
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    Na, ja, in der Doku steht "Timer". Das muss eben nicht NSTimer heißen. Es ist ganz gewiss so, dass NSTimer ein Wrapper ist, es also noch einen Timer im System gibt. Anders etwa als bei NSView, den es im System nicht geben dürfte. (Jedenfalls sehe ich dort keine Notwendigkeit.)

    Apple schreibt die Doku aber sicherlich für alle Entwickler. Also insbesondere auch für die, die sich nicht so tief in den Cocoa- und Foundation-Eingeweiden auskennen wie Du. Somit verstehe ich das Wort Timer als Objekt vom Typ NSTimer. Von einem internen Timer zu reden, auf den der Nutzer sowieso keinen Zugriff hat, macht meiner Meinung nach hier auch keinen Sinn.

    Amin Negm-Awad schrieb:

    Als Beweis reicht mir der RC von mattik. Einfach mal einen Dangling-Pointer zu erzeugen, reicht ganz gewiss nicht. Wieso sollte der Speicherplatz belegt werden?
    Den Timer in einer Retained-Property zu speichern ist sicherlich sauberer, als in einer Assigned-Property. Ich habe ja auch keinen Beweis sondern nur eine Begründung geliefert. Aber auch Mattiks (sicherlich stärkere Begründung) ist streng genommen kein Beweis. Wer weiß, wer da noch alles die Eigentümerschaft haben will. Aber wem schreibe ich das ;)
    „Meine Komplikation hatte eine Komplikation.“
  • Amin Negm-Awad schrieb:

    Ich hatte das mal getestet und es funktionierte nicht.

    Für eine Referenz auf die Methode brauchst du ja kein Cocoa-Objekt. Timer fangen ja viel tiefer im System an.


    Nee, nicht für die Referenz auf die Methode, eine Referenz auf den NSTimer. Der wird Deiner timerFired-Methode als Parameter mitgegeben:

    - (void) timerFired: (NSTimer*)timer
    Multigrad - 360°-Produktfotografie für den Mac
  • mattik schrieb:

    Amin Negm-Awad schrieb:

    Ich hatte das mal getestet und es funktionierte nicht.

    Für eine Referenz auf die Methode brauchst du ja kein Cocoa-Objekt. Timer fangen ja viel tiefer im System an.


    Nee, nicht für die Referenz auf die Methode, eine Referenz auf den NSTimer. Der wird Deiner timerFired-Methode als Parameter mitgegeben:

    - (void) timerFired: (NSTimer*)timer


    Arg, das stimmt allerdings.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • macmoonshine schrieb:

    Amin Negm-Awad schrieb:

    Na, ja, in der Doku steht "Timer". Das muss eben nicht NSTimer heißen. Es ist ganz gewiss so, dass NSTimer ein Wrapper ist, es also noch einen Timer im System gibt. Anders etwa als bei NSView, den es im System nicht geben dürfte. (Jedenfalls sehe ich dort keine Notwendigkeit.)

    Apple schreibt die Doku aber sicherlich für alle Entwickler. Also insbesondere auch für die, die sich nicht so tief in den Cocoa- und Foundation-Eingeweiden auskennen wie Du. Somit verstehe ich das Wort Timer als Objekt vom Typ NSTimer. Von einem internen Timer zu reden, auf den der Nutzer sowieso keinen Zugriff hat, macht meiner Meinung nach hier auch keinen Sinn.

    Amin Negm-Awad schrieb:

    Als Beweis reicht mir der RC von mattik. Einfach mal einen Dangling-Pointer zu erzeugen, reicht ganz gewiss nicht. Wieso sollte der Speicherplatz belegt werden?
    Den Timer in einer Retained-Property zu speichern ist sicherlich sauberer, als in einer Assigned-Property. Ich habe ja auch keinen Beweis sondern nur eine Begründung geliefert. Aber auch Mattiks (sicherlich stärkere Begründung) ist streng genommen kein Beweis. Wer weiß, wer da noch alles die Eigentümerschaft haben will. Aber wem schreibe ich das ;)


    Na, das ist ja keine Begründung. Bei einer Begründung geht es ja drum, warum etwas so ist, nicht, dass es so ist. Du sagtest aber ja, dass es so ist (Test).
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?