Programmieren mit Swift - Für macOS und iOS
Programmieren mit Swift - Für macOS und iOS
Speichern von Sprache

Soll ein Programm eine Datei speichern, stellen sich für gewöhnlich zwei Fragen, die der Benutzer beantworten muss:

Wie soll die Datei heißen?
Wohin soll sie gespeichert werden?

Für den Entwickler stellt sich die zusätzliche Frage, wie der Benutzer der Anwendungen diese Informationen mitteilen kann.
Natürlich ist dieses Problem nicht neu und für diese Situation bestens geeignet ist die Klasse NSSavePanel. Ein NSSavePanel ist ein standardisiertes Fenster, das Sie bestimmt schon aus unzähligen anderen Programmen kennen. Es ist die typische Abfrage, wenn man Dateien speichern will.

Wieder einmal nimmt Ihnen das Cocoa-Framework die Arbeit ab, und Sie müssen das Rad nicht neu erfinden. Obwohl es sich um ein Fenster handelt, wird ein NSSavePanel nicht mit dem Interface Builder erstellt.

Ändern Sie die saveToFile-Methode in Ihrem Projekt wie folgt:
-(IBAction)saveToFile:(id)sender
{
    NSSavePanel *mySavePanel = [NSSavePanel savePanel];
    [mySavePanel setRequiredFileType:
@"aiff"];
    [mySavePanel setTitle:
@"Sprachausgabe speichern"];
    [mySavePanel runModal];
}
Es wird eine Instanz eines NSSavePanel mit dem Namen mySavePanel erzeugt. Zusätzlich wird mit aiff ein Dateityp bestimmt, den die gespeicherte Sprachedatei haben soll. Mit setTitel wird die Titelleiste des Fensters geändert und durch den Aufruf von runModal, das NSSavePanel letztendlich angezeigt. Sie können diese Methode schon testen und Sie erhalten ein Fenster, das wie folgt aussieht:
stacks_image_6DA9F139-38AF-48BF-B21D-94C1988994E9
Oder, wenn die erweiterten Optionen eingeblendet sind, so:
stacks_image_6825AF0A-3586-4540-A34B-B45617CC2B75
Leider speichert dieses Fenster noch keine Dateien, es liefert nur eine Auswahl für einen Dateinamen samt Pfad. Es ist sogar noch etwas mehr Detailarbeit nötig, denn in der Regel will man die Datei auch nur speichern, wenn der Benutzer den Save-Button angeklickt hat. Beim Anklicken von Cancel soll nichts geschehen. So eine Abfrage fehlt in diesem Code aber und der Aufruf von runModal sollte so aussehen:
if([mySavePanel runModal] == NSOKButton)
{

}
Zwischen diese geschweiften Klammern gehört dann der Code, welcher die Sprach-Datei tatsächlich speichert. Das ist aber mit geringem Aufwand möglich, denn der NSSpeechSynthesizer hat eine Methode, die diese Aufgabe übernehmen kann, nämlich startSpeakingString toURL. Alles was fehlt ist eine NSURL, die den Dateinamen und Pfad enthält. Diesen Wert (als NSString) bekommt man, wenn man die Nachricht filename an das NSSavePanel Objekt sendet.
if([mySavePanel runModal] == NSOKButton)
{
    NSString *myText;
    myText = [[inputTextView textStorage] string];

    [mySpeechSynth setVoice:[[NSSpeechSynthesizer availableVoices]
     objectAtIndex:[voicesCombo indexOfSelectedItem]]];

    NSURL *myURL = [NSURL URLWithString:[mySavePanel filename] ];

    [mySpeechSynth startSpeakingString:myText toURL:myURL];
}
Gelegentlich gibt es Missverständnisse bei der Programmierung von Fenstern, weshalb an dieser Stelle noch auf einen besonderen Sachverhalt hingewiesen werden soll. Fenster hören, nachdem sie geschlossen wurden, nicht auf zu existieren! Gut deutlich wird das hier am NSSavePanel-Objekt. Natürlich wird das Fenster nach Beendigung des runModal-Befehls geschlossen, aber es ist noch weiterhin als Objekt im Speicher vorhanden. Deshalb kann man sich auch ohne Probleme zu einem späteren Zeitpunkt noch immer den ausgewählten Dateinamen von diesem Objekt holen, obwohl es nicht mehr als sichtbares Fenster aktiv ist.