Wie verwende ich NSTimer?

344

Wie benutze ich eine NSTimer? Kann mir jemand Schritt für Schritt Anweisungen geben?

lab12
quelle
1
Ich habe parametrische Informationen über pravinmagdum.wordpress.com/2010/12/30/how-to-use-nstimer. Ich kann es mir ansehen. Kann für Sie hilfreich sein

Antworten:

616

Zunächst möchte ich Sie auf die Cocoa / CF-Dokumentation aufmerksam machen (die immer eine gute erste Anlaufstelle ist). In den Apple-Dokumenten befindet sich oben in jedem Referenzartikel ein Abschnitt mit dem Namen "Companion Guides", in dem Anleitungen für das zu dokumentierende Thema aufgeführt sind (falls vorhanden). Zum Beispiel mit NSTimer, die Dokumentation listet zwei Begleiter Führungen:

Für Ihre Situation ist der Artikel über Timer-Programmierthemen wahrscheinlich am nützlichsten, während Threading-Themen verwandt sind, jedoch nicht direkt mit der zu dokumentierenden Klasse. Wenn Sie sich den Artikel über Timer-Programmierthemen ansehen, ist er in zwei Teile unterteilt:

  • Timer
  • Timer verwenden

Für Artikel, die dieses Format annehmen, gibt es häufig eine Übersicht über die Klasse und deren Verwendung sowie einen Beispielcode für deren Verwendung, in diesem Fall im Abschnitt "Verwenden von Timern". Es gibt Abschnitte zu "Erstellen und Planen eines Timers", "Stoppen eines Timers" und "Speicherverwaltung". Aus dem Artikel geht hervor, dass ein geplanter, sich nicht wiederholender Timer wie folgt erstellt werden kann:

[NSTimer scheduledTimerWithTimeInterval:2.0
    target:self
    selector:@selector(targetMethod:)
    userInfo:nil
    repeats:NO];

Dadurch wird ein Timer erstellen , die nach 2,0 Sekunden abgefeuert wird , und fordert targetMethod:auf selfmit einem Argument, das ein Zeiger auf die ist NSTimerInstanz.

Wenn Sie sich die Methode dann genauer ansehen möchten, können Sie auf die Dokumente zurückgreifen, um weitere Informationen zu erhalten. Es gibt jedoch auch Erklärungen zum Code.

Wenn Sie einen sich wiederholenden Timer stoppen möchten (oder einen sich nicht wiederholenden Timer stoppen möchten, bevor er ausgelöst wird), müssen Sie einen Zeiger auf die erstellte NSTimerInstanz behalten . Oft muss dies eine Instanzvariable sein, damit Sie in einer anderen Methode darauf verweisen können. Sie können dann invalidatedie NSTimerInstanz aufrufen :

[myTimer invalidate];
myTimer = nil;

Es wird auch empfohlen nil, die Instanzvariable zu löschen (wenn beispielsweise Ihre Methode, die den Timer ungültig macht, mehrmals aufgerufen wird und die Instanzvariable nicht auf gesetzt nilund die NSTimerInstanz freigegeben wurde, wird eine Ausnahme ausgelöst).

Beachten Sie auch den Punkt zur Speicherverwaltung am Ende des Artikels:

Da die Ausführungsschleife den Timer verwaltet, ist es aus Sicht der Speicherverwaltung normalerweise nicht erforderlich, einen Verweis auf einen Timer zu behalten, nachdem Sie ihn geplant haben . Da der Timer als Argument übergeben wird, wenn Sie seine Methode als Selektor angeben, können Sie einen sich wiederholenden Timer gegebenenfalls innerhalb dieser Methode ungültig machen . In vielen Situationen möchten Sie jedoch auch die Option, den Timer ungültig zu machen - möglicherweise sogar noch vor dem Start. In diesem Fall müssen Sie einen Verweis auf den Timer behalten, damit Sie ihm bei Bedarf eine ungültige Nachricht senden können. Wenn Sie einen außerplanmäßigen Timer erstellen (siehe „Außerplanmäßige Timer“), müssen Sie einen starken Verweis auf den Timer beibehalten (in einer Umgebung mit Referenzzählung behalten Sie ihn bei), damit er nicht freigegeben wird, bevor Sie ihn verwenden.

Alex Rozanski
quelle
Okk, eine Frage, was würde ich als meinen Code eingeben, der alle zwei Sekunden ausgeführt wird?
lab12
Sie würden Pass YESfür , repeats:wenn Sie anrufen scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:. Wenn Sie dies tun, stellen Sie sicher, dass Sie einen Verweis auf die NSTimerInstanz behalten (dieser wird von der Methode zurückgegeben), und befolgen Sie den oben beschriebenen Punkt zur Speicherverwaltung.
Alex Rozanski
Nein, wo würde ich meinen Code ablegen, der alle 2 Sekunden gestartet wird? Nehmen wir zum Beispiel an, ich wollte, dass alle 2 Sekunden ein Piepton ertönt. Wo würde ich den Piepton-Rauschcode einfügen?
lab12
In der Methode, die Sie mit targetund angeben selector. Wenn sich beispielsweise Ihr Ziel selfund der Selektor befinden timerMethod:, wird die Methode timerMethod:definiert , die beim Auslösen des Timers aufgerufen wird self. Sie können dann den gewünschten Code in diese Methode einfügen, und die Methode wird immer dann aufgerufen, wenn der Timer ausgelöst wird. Beachten Sie, dass die beim Auslösen des Timers aufgerufene Methode (die Sie als übergeben selector:) nur ein Argument annehmen kann (das beim Aufrufen ein Zeiger auf die NSTimerInstanz ist).
Alex Rozanski
Entschuldigung, gemeint "definiert am self"
Alex Rozanski
331

Es gibt verschiedene Möglichkeiten, einen Timer zu verwenden:

1) Geplanter Timer & mit Selektor

NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
                      target: self
                      selector:@selector(onTick:)
                      userInfo: nil repeats:NO];
  • Wenn Sie Wiederholungen auf NEIN setzen, wartet der Timer 2 Sekunden, bevor der Selektor ausgeführt wird, und stoppt danach.
  • Bei Wiederholung: JA, der Timer startet sofort und wiederholt alle 2 Sekunden den Selektor.
  • Um den Timer zu stoppen, rufen Sie die -invalidate-Methode des Timers auf: [t invalidate];

Als Randnotiz können Sie anstelle eines Timers, der sich nicht wiederholt und den Selektor nach einem bestimmten Intervall aufruft, eine einfache Anweisung wie die folgende verwenden:

[self performSelector:@selector(onTick:) withObject:nil afterDelay:2.0];

Dies hat den gleichen Effekt wie der obige Beispielcode. Wenn Sie den Selektor jedoch jedes n-te Mal aufrufen möchten, verwenden Sie den Timer mit Wiederholungen: YES;

2) selbst geplanter Timer

NSDate *d = [NSDate dateWithTimeIntervalSinceNow: 60.0];
NSTimer *t = [[NSTimer alloc] initWithFireDate: d
                              interval: 1
                              target: self
                              selector:@selector(onTick:)
                              userInfo:nil repeats:YES];

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:t forMode: NSDefaultRunLoopMode];
[t release];
  • Dadurch wird ein Timer erstellt, der an einem von Ihnen festgelegten benutzerdefinierten Datum (in diesem Fall nach einer Minute) startet und sich jede Sekunde wiederholt

3) außerplanmäßiger Timer & Aufruf

NSMethodSignature *sgn = [self methodSignatureForSelector:@selector(onTick:)];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sgn];
[inv setTarget: self];
[inv setSelector:@selector(onTick:)];

NSTimer *t = [NSTimer timerWithTimeInterval: 1.0
                      invocation:inv 
                      repeats:YES];

und danach starten Sie den Timer manuell, wann immer Sie dies benötigen:

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];



Und als Hinweis sieht die onTick: -Methode folgendermaßen aus:

-(void)onTick:(NSTimer *)timer {
   //do smth
}
Woofy
quelle
Ok, aber Sie sehen, ich möchte die Transparenz meiner App verringern, daher weiß ich nicht, wie ich das mit dem NSTimer anwenden soll
lab12
24
Meine Güte, diese Leute heute ... stimmen von mir ab, weil Sie das von Anfang an nicht angegeben haben und lassen Sie uns vergeblich schreiben!
Woofy
28
Du hast nicht umsonst geschrieben. Das ist eine gute Info!
Willc2
Wie kann ich in Methode 2, "selbst geplanter Timer", den Timer stoppen, wenn ich möchte?
Satyam
1
@Satyamsvv, Sie können den Timer stoppen, indem Sie eine andere Methode aufrufen, die Folgendes enthält: [Timer ungültig machen]; Timer = Null;
Kimpoy
59

Etwas wie das:

NSTimer *timer;

    timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
                     target: self
                     selector: @selector(handleTimer:)
                     userInfo: nil
                     repeats: YES];
ennuikiller
quelle
14
Immer noch stark ... auch 2014!
Muruganandham K
5
#import "MyViewController.h"

@interface MyViewController ()

@property (strong, nonatomic) NSTimer *timer;

@end

@implementation MyViewController

double timerInterval = 1.0f;

- (NSTimer *) timer {
    if (!_timer) {
        _timer = [NSTimer timerWithTimeInterval:timerInterval target:self selector:@selector(onTick:) userInfo:nil repeats:YES];
    }
    return _timer;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}

-(void)onTick:(NSTimer*)timer
{
    NSLog(@"Tick...");
}

@end
Dan
quelle
Irgendwie schafft es einen Aufbewahrungszyklus, so dass der MyViewControllernie freigegeben wird.
Darrarski
5
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerCalled) userInfo:nil repeats:NO];

-(void)timerCalled
{
     NSLog(@"Timer Called");
     // Your Code
}
Mohit
quelle
wo hast du das geschrieben
Mohit
1
@JigneshB Diese Antwort handelt nur von der Verwendung von NSTimer, nicht von der Verwendung im Hintergrund
Mohit
Ich schrieb in Hintergrundmethode dh - (void) applicationDidEnterBackground: (UIApplication *) application {}
Jignesh B
mit wiederholtem Modus JA
Jignesh B
In der Dokumentation von Apple wird die Signatur der Rückrufmethode sehr genau beschrieben. Dein ist falsch.
Nikolai Ruhe
2

Den Antworten fehlt eine bestimmte Tageszeit. Hier ist die nächste Stunde:

NSCalendarUnit allUnits = NSCalendarUnitYear   | NSCalendarUnitMonth |
                          NSCalendarUnitDay    | NSCalendarUnitHour  |
                          NSCalendarUnitMinute | NSCalendarUnitSecond;

NSCalendar *calendar = [[ NSCalendar alloc]  
                          initWithCalendarIdentifier:NSGregorianCalendar];

NSDateComponents *weekdayComponents = [calendar components: allUnits 
                                                  fromDate: [ NSDate date ] ];

[ weekdayComponents setHour: weekdayComponents.hour + 1 ];
[ weekdayComponents setMinute: 0 ];
[ weekdayComponents setSecond: 0 ];

NSDate *nextTime = [ calendar dateFromComponents: weekdayComponents ];

refreshTimer = [[ NSTimer alloc ] initWithFireDate: nextTime
                                          interval: 0.0
                                            target: self
                                          selector: @selector( doRefresh )
                                          userInfo: nil repeats: NO ];

[[NSRunLoop currentRunLoop] addTimer: refreshTimer forMode: NSDefaultRunLoopMode];

Ersetzen Sie "doRefresh" natürlich durch die gewünschte Methode Ihrer Klasse

Versuchen Sie, das Kalenderobjekt einmal zu erstellen und die allUnits aus Effizienzgründen statisch zu machen.

Das Hinzufügen einer Stunde zur Komponente funktioniert einwandfrei, es ist kein Mitternachtstest erforderlich ( Link )

gjpc
quelle