Der sanfte Weg von Objective-C zu Swift

Know-how  –  0 Kommentare

Swift soll Objective-C-Entwicklern eine arbeitssparende Sprachalternative sein. Trotz grundsätzlichem Interesse will man jedoch häufig nicht alle alten Projekte über den Haufen werfen. Zeit, über Migrationswege nachzudenken.

Kaum ein Jahr nach ihrer offiziellen Vorstellung im Rahmen der WWDC 2014 hat Apples neue Programmiersprache Swift bereits eine breite Fan-Gemeinde gefunden und klettert in den Rankings der beliebtesten Programmiersprachen (siehe zum Beispiel RedMonk) stetig nach oben. Ein Platz unter den Top 10 scheint nur noch eine Frage der Zeit.

Michael Stal hat bereits in seinem Artikel "Extended Tour de Swift" ausführlich über die grundlegenden Konzepte der Sprache berichtet und dabei aufgezeigt, wie viel einfacher sich die Entwicklung von iOS- und OS-X-Anwendungen mit Swift gestaltet. Mit der kürzlich veröffentlichten Version 1.2 hat Apple noch einmal kräftig nachgelegt und neben einigen nützlichen Feature auch für eine ordentliche Performance-Steigerung gesorgt. Wenn es nach Wil Shipley, dem bekannten Mac-Entwickler und Mastermind von Delicious Monster, geht, dann sollte zukünftig kein Entwickler mehr mit Objective-C – der "crapshack of a language" (Mistbude von einer Sprache), wie er sie bezeichnete – arbeiten müssen.

Für neue Projekte liegt es also nahe, sie direkt in Swift zu realisieren. Wie aber sieht es aus, wenn man nicht die Chance hat, auf der grünen Wiese zu starten, sondern ein umfangreiches Objective-C-Projekt mit Swift-Code erweitern oder gar vollständig in Richtung Swift migrieren will. Auch hier hat Apple Vorsorge getroffen und liefert das eine oder andere Hilfsmittel frei Haus.

Mix and Match

Damit die Migration bestehender Projekte möglichst einfach und reibungslos über die Bühne geht, entwickelte das Team hinter Swift die Sprache von Anfang an mit der größtmöglichen Kompatibilität zu Objective-C im Hinterkopf. Das geschah unter anderem deshalb, weil Apple den eigenen Code noch nicht komplett umgestellt hatte und bei bestimmten Frameworks wahrscheinlich nie umstellen wird.

Aus dem Grund soll es – Apple zufolge – problemlos möglich sein, beide Sprachen in einem Projekt zu mischen und bereits eingesetzte Frameworks weiterzuverwenden. Was genau in diesem Zusammenhang unter "problemlos" zu verstehen ist, wird der Artikel im weiteren Verlauf zeigen.

Die Möglichkeit zum Mischen beider Programmiersprachen ist ein großer Vorteil bei der Migration, da man nach und nach Klasse für Klasse einzeln umstellen kann – und nicht alles auf einmal. Das würde wahrscheinlich jeden zeitlichen und monetären Rahmen sprengen und wäre damit für die meisten Projekte schlichtweg nicht praktikabel.

Der Anfang jeder Migration zu Swift ist vergleichsweise leicht: Man nehme Apples Entwicklungsumgebung Xcode ab Version 6, die über den Mac App Store frei verfügbar ist, und öffne damit das vorhandene Projekt. Sobald nun per File | New | File | Source (iOS oder OS X) | Swift File die erste Swift-Datei angelegt ist, bietet Xcode automatisch an, einen Bridging Header anzulegen.

Bridging Header lassen sich automatisch erstellen (Abb. 1).

Der Bridging Header ist nötig, um Objective-C-Code mit Swift nutzen zu können. Xcode legt dazu eine Header-Datei mit dem Namen <Modulname>-Bridging-Header.h an und bindet ihn in den Build Settings unter Swift Compiler | Code Generation ein.

//
// Use this file to import your target's public
// headers that you would like to expose to Swift.
//
#import <AFNetworking/AFNetworking.h>
#import "ViewController.h"

Hat man dem Angebot, einen Header zu generieren, zugestimmt, nimmt man dort nach und nach alle Imports auf, die der Swift-Code benötigt. Für die Imports der eigenen Header gilt, dass sie mit jeder migrierten Klasse weniger werden. Am Ende der Überführung sollten nur noch solche vorhanden sein, die zu externen Frameworks gehören.

Sobald die Abhängigkeiten geladen sind, lässt sich aus jeder Swift-Klasse auf die importierten Schnittstellen zugreifen. Der bestehende Code wird dabei mit der entsprechenden Swift-Syntax angezeigt. So wird zum Beispiel aus

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager
manager];
[manager GET:@"http://examples.com/json" parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];

folgender Swift-Code:

let manager = AFHTTPRequestOperationManager()
manager.GET( "http://examples.com/json",
parameters: nil,
success: { (operation, responseObject) in
NSLog("JSON: \(responseObject)")
},
failure: { (operation, error) in
NSLog("Error: \(error)")
})

Am obigen Beispiel lässt sich erkennen, wie die Syntax von Swift zur besseren Lesbarkeit beiträgt. Beim Konvertieren übersetzt Xcode alle Initializer automatisch und ändert eventuelle Zusätze nach dem Muster initWithBaseURL:(NSURL *)url in init(baseUrl: NSURL).