Programmieren mit Swift - Für macOS und iOS
Programmieren mit Swift - Für macOS und iOS
Einführung NSTimer

Um die Klasse NSTimer mit ihren Möglichkeiten kennenzulernen, sollten Sie auch für diese Lektion selbstverständlich wieder eine Cocoa Anwendung erstellen. Nennen Sie das Projekt „lektionTimer“. Erzeugen Sie zusätzlich wieder eine weitere Objective-C Klasse, MyController, die Sie um die folgenden zwei Methoden erweitern.
-(void)awakeFromNib
{
    NSTimer *timer;
    timer = [NSTimer scheduledTimerWithTimeInterval:
1
                        target:
self
                        selector:@selector(tick:)
                        userInfo: nil
                        repeats: YES];

}

- (
void)tick:(NSTimer *)theTimer
{
    NSBeep();
}

Natürlich müssen sie auch wieder von dieser Klasse eine Instanz erzeugen, anderenfalls würde awakeFromNib nicht ausgeführt. Doppelklicken Sie in der Projektübersicht auf die mainMenu.xib, um den Interface Builder zu starten und ziehen Sie ein NSObject aus der Palette auf das Haupfenster des Interface Builder.
stacks_image_A9B96A6A-2484-469C-8E28-F4D7A758E525
Setzen Sie nun noch die Identiät (Identity) dieses Objektes mit dem Inspector auf „MyController“, in dem Sie diese Klasse aus der ComboBox auswählen. Sie haben zwar weder Outlets noch Actions, aber die brauchen Sie auch (noch) nicht.
stacks_image_0711D58D-A704-44AC-8B38-76CD2E640B06
Speichern Sie die Änderungen im Interface Builder und starten Sie Ihre Anwendung durch Anklicken von Build and Run oder durch die Tastenkombination cmd + Enter in Xcode.

Ein interessantes Programm haben Sie da. Es tut zwar nichts Weltbewegendes, sondern spielt nur ein akustisches Signal ab, aber das tut es automatisch und immer wieder, bis Sie das Programm beenden. Das macht der Timer.

Es gibt viele Möglichkeiten einen Timer zu erzeugen, die oben gezeigte ist wahrscheinlich die einfachste. Der scheduledTimer wird sofort aktiv und führt die im Selector angegebene Methode (tick) aus. Das Intervall ist eine Sekunde und der Parameter „repeats“ bestimmt, dass dieser Vorgang automatisch wiederholt werden soll.

Im nächsten Schritt werden Sie den Timer durch Button ein- und ausschalten. Wichtig ist, dass Sie den NSTimer in der Klasse deklarieren und nicht mehr in einer Methode. Entfernen Sie die awakeFromNib-Methode am besten komplett. Zusätzlich benötigen Sie zwei Methoden, mit denen Sie den Timer steuern werden.

Ihre MyController.h Datei sollte so aussehen:
#import <Cocoa/Cocoa.h>

@interface MyController : NSObject {

    NSTimer *myTimer;
}

- (
IBAction)startMyTimer:(id)sender;
- (
IBAction)stopMyTimer:(id)sender;

@end
Und dementsprechend die Codedatei:
#import "MyController.h"

@implementation MyController

- (
IBAction)startMyTimer:(id)sender
{
    [myTimer invalidate];

    myTimer = [NSTimer scheduledTimerWithTimeInterval:
1 target:self selector:
     @selector(tick:) userInfo:nil repeats:YES];

    [myTimer fire];
}

- (
IBAction)stopMyTimer:(id)sender
{
    [myTimer invalidate];
    myTimer =
nil;
}

- (
void)tick:(NSTimer *)theTimer
{
    NSBeep();
}

@end
Jetzt benötigen Sie nur noch ein Programmfenster mit zwei Button, um die beiden Action auszulösen und schon können Sie Ihr verbessertes Programm testen. Vergessen Sie nicht, im Interface Builder die nötigen Verbindungen zu ziehen.
stacks_image_E9A99FEF-8372-4683-9AD6-D75F3D91D95F
Der Aufruf von invalidate beendet den NSTimer, während der Aufruf von fire eine sofortige Ausführung der dem Timer zugewiesenen Methode bewirkt. Entfernen Sie diesen Befehl und Sie werden merken, dass zwischen dem Anklicken des Starten-Button und dem ersten Signal Zeit vergeht und Sie nicht sofort eine Rückmeldung bekommen.

Es ist wichtig zu wissen, was im Hintergrund passiert. Wenn Sie einen scheduledTimerWithTimeInterval erzeugen, wird dieser automatisch der aktuellen NSRunLoop hinzugefügt. Ein NSRunLoop kann man am besten als Programmschleife beschreiben, die jegliche Interaktion mit dem Programm, wie zum Beispiel von Maus oder Tastatur, verarbeitet. Sie brauchen kein NSRunLoop zu erzeugen, Ihr Programm hat schon so eine Schleife. Das ist nicht besonders überraschend, denn Ihre Eingaben und Klicks werden ja schon verarbeitet. Und zu genau dieser NSRunLoop, eben der currentRunLoop, wird Ihr Timer hinzugefügt. Es gibt einen anderen Timer, bei welchem dieses nicht mehr automatisch geschieht.

Ändern Sie ihren Code wie folgt:
- (IBAction)startMyTimer:(id)sender
{
    [myTimer invalidate];
    myTimer = [NSTimer timerWithTimeInterval:
1.0 target:self selector:
     @selector(tick:) userInfo:nil repeats:YES];

    [[NSRunLoop currentRunLoop] addTimer:myTimer forMode: NSDefaultRunLoopMode];
}
Sie werden keine Änderung bei der Ausführung des Programms feststellen. Aber wie Sie an den Anweisungen erkennen können, wird sehr schön deutlich, wie der Timer dem currentRunLoop hinzugefügt wurde.
Interessant ist auch der Modus NSDefaultRunLoopMode. Ändern Sie diese Einstellung mal zu NSEventTrackingRunLoopMode. In diesem Fall läuft der Timer nur, wenn die Maus in einem von NSControl abgeleiteten Steuerelement gedrückt und gehalten wird. Klicken Sie auf „Timer starten“ in Ihrem Programm, wird nicht viel passieren, beginnen Sie aber dann, Ihr Programmfenster zu skalieren, werden sehen, wie sich dieser Timer verhält.

Schon an dieser kleinen Einführung erkennen Sie, dass Timer ein sehr komplexes Thema sind. Die wichtigsten Grundlagen sind Ihnen aber jetzt vertraut. Im nächsten Kapitel werden Sie eine Stoppuhr programmieren.

nächste Seite