Programmieren mit Swift - Für macOS und iOS
Programmieren mit Swift - Für macOS und iOS
Delegates

Sie haben inzwischen einiges über Klassen in Objective-C gelernt. Klassen haben Methoden und Instanzvariablen, was für einen erfahrenen Programmierer nichts Ungewöhnliches sein wird. Was Sie vielleicht nicht wissen, viele der Klassen im Cocoa Framework haben eine spezielle Instanzvariable mit Namen delegate. Über dieses delegate-Objekt ist es einem Objekt möglich, sich mitzuteilen und Aufgaben an andere Objekte zu delegieren. Das delegate bestimmt wem, also welchem anderen Objekt, sich das Objekt mitteilt. Es gibt verschiedene Situationen, in denen man ohne delegates nicht arbeiten könnte.

Um delegates zu verstehen, sollten Sie sich zunächst die Funktion des letzten Programms, des NSSpeechSynthesizer, genau ansehen. Sie haben sicher gemerkt, dass das Programm weiterhin bedienbar bleibt, während die Sprachausgabe läuft. Sie können das Fenster verschieben oder sogar die Sprachausgabe erneut starten, während schon eine Ausgabe abgespielt wird. Offensichtlich läuft die Sprachausgabe parallel zum Rest des Programms. Die Anwendung wartet nicht auf das Ende der Sprachausgabe, bevor es weitere Anweisungen im restlichen Code ausführt.

Dieser Umstand wirkt auf den ersten Blick sehr praktisch, hat aber einen kleinen Schönheitsfehler. Da das Programm nicht auf die Abarbeitung einer Anweisung, in diesem Fall startSpeakingString des NSSpeechSynthesizer, wartet, erhält man auch keine Informationen darüber, wann diese Anweisung denn tatsächlich komplett abgearbeitet wurde. Nehmen wir einmal an, Sie möchten nach dem Ende der Sprachausgabe einen Signalton abspielen oder eine weitere Sprachausgabe starten, sobald die Erste beendet ist. Wie würden Sie das tun? Die Sprachausgabe kann ja je nach Länge des Textes mehrere Sekunden dauern. Wann der nächste Befehl folgen wird, ist schwer zu ermitteln. Noch schwieriger zu beantworten ist die Frage, was denn die Anwendung tun soll, bis es soweit ist.

Genau zu diesem Zweck gibt es delegates, denn über ein delegate kann ein Objekt Nachrichten an ein anderes Objekt senden. Der NSSpeechSynthesizer sendet zum Beispiel eine Nachricht, sobald die Sprachausgabe beendet wurde. Das passiert automatisch. Man muss dem NSSpeechSynthesizer-Objekt nur sagen, wohin er diese Nachricht senden soll.

Von solchen Nachrichten gibt es eine ganze Menge. Ein Fenster (NSWindow) sendet zum Beispiel Nachrichten, wenn seine Größe oder Position verändert oder es minimiert wurde.
Natürlich haben Sie in den vorherigen Programmbeispielen davon nichts gemerkt. Und genau dies ist einer der großen Vorteile von delegates. Der delegate eines Objektes bestimmt nur wohin die Nachrichten des Objektes gesendet werden sollen. Sie sind nicht verpflichtet, diese Nachrichten auswerten oder einen delegate zu bestimmen. Solange Sie diese Nachrichten nicht entgegennehmen, haben sie keine Auswirkungen. (Um genau zu sein, werden die Nachrichten erst gar nicht gesendet, wenn kein Empfänger vorhanden ist.) Haben Sie aber eine Methode, die einem Aufruf entspricht, wird diese automatisch ausgeführt, sobald die entsprechende Nachricht empfangen wurde.

Verändern Sie nun den Programmcode aus dem letzten Beispiel wie im folgenden Code angegeben. Der Befehl setDelegate bestimmt, wohin die Nachrichten des Objektes meinSpeechSynth gesendet werden sollen. Hier bedeutet self, dass es die Klasse sein soll, in der auch schon die Instanz des NSSpeechSynthesizer erstellt wurde, nämlich MyController. Der Controller benachrichtigt sich selbst, auch das ist ohne Probleme möglich.
-(void)awakeFromNib
{
    mySpeechSynth = [[NSSpeechSynthesizer alloc] initWithVoice:
nil];
    [mySpeechSynth setDelegate:
self];
}
Von nun an kommen die Mitteilungen der NSSpeechSynthesizer Instanz beim MyController Objekt an, denn mit setDelegate wurde festgelegt, an wen der NSSpeechSynthesizer seine Aufgaben delegieren soll. Will man die gesendeten Nachrichten auswerten, genügt es, eine genau definierte Methode zu implementieren.
-(void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:
     (
BOOL) finishedSpeaking
{
    NSBeep();
}
Passen Sie gut auf, Sie dürfen sich bei dieser Methodendefinition keinen Schreibfehler erlauben, der Compilier kann hier wenig für Sie tun. Ein Schreibfehler würde zwar keine schlimmen Folgen haben, aber die Methode, die sonst automatisch ausgeführt würde, würde eben nicht ausgeführt, da sie nicht mehr der vom NSSpeechSynthesizer abgesendeten Nachricht entspricht. Sie müssen diese Methode auch nicht in der Header-Datei MyController.h deklarieren.

nächste Seite