Swift 5 ist da

Warum Apps ab iOS 12.2 kleiner werden

08.03.2019 von André Martin
Apples selbst entwickelte Programmiersprache „Swift“ geht in die fünfte Generation und es tut sich einiges. Endlich bekommt Swift die lang erwartete „ABI-Stabilität“, doch auch in der Sprache selbst gibt es viele Verbesserungen.

Was ist ABI-Stabilität und warum ist das so wichtig? Programmierer merken nichts davon, wenn Swift die so genannte ABI-Stabilität erteilt wird, denn das hat nur Auswirkungen im „Maschinenraum“ von Swift. ABI steht für „Application Binary Interface“. Es definiert, wie genau Funktionen, Variablen, Konstanten etc. im Speicher abgelegt werden. Ist das einmal festgelegt, darf es sich in zukünftigen Swift-Versionen nicht mehr ändern, sonst laufen ältere Apps nicht mehr. Deswegen muss man sich ganz genau überlegen, wie das finale ABI aussehen soll, bevor man es ein für allemal festlegt. Vor allem im Hinblick auf zukünftige Erweiterungen der Sprache.

Mit Swift 5 kommt die ABI-Stabilität.
Foto: Apple

Apple hat sich deswegen wirklich lange Zeit dafür genommen. Ursprünglich sollte die ABI-Stabilität schon mit Swift 3 kommen, doch sie wurde verschoben. Dann hieß es, sie komme mit Swift 4, sie wurde wiederum verschoben. Nun kommt Swift 5 und endlich erklärt Apple das Swift-ABI für stabil.

Doch was genau bedeutet dieser große Schritt für Entwickler und Anwender? Aufatmen: Entwickler brauchen sind keine Sorgen zu machen, denn der Quellcode ihrer Apps bleibt unberührt. Es gibt aber tatsächlich Auswirkungen für den Anwender – sogar sehr positive. Bislang war es so, dass jede einzelne App sämtliche Swift-Funktionsbibliotheken enthalten musste, die sie zur Laufzeit benutzt. Diese Bibliotheken können, je nach Funktionsumfang der App mehrere zig Megabyte groß sein. Nach der endgültigen Festlegung der ABI-Stabilität kann Apple die Bibliotheken fest ins iOS integrieren, alle Apps greifen dann auf diese, nur einmal vorhandenen Bibliotheken zu. Die Folge: Apps werden kleiner, sie brauchen weniger Platz auf dem iPhone oder iPad! Eine gute Sache!

Kleinere Apps

Doch wie viel macht das in der Praxis aus? Genau das wollen wir herausbekommen. Ab Xcode 10.2 Beta (erschien im Januar 2019) und iOS 12.2 Beta ist die ABI-Stabilität gegeben. Wir installieren die Betaversion von Xcode 10.2 auf unserem Entwicklungs-Mac. Achtung, diese Betaversion läuft nur unter macOS 10.14 Mojave. Ältere macOS-Versionen bleiben außen vor und auch die aktuellen macOS-Betaversionen eignen sich nicht nicht für Xcode 10.2.

Wir erzeugen ein neues leeres Swift-Project (Single View), und platzieren lediglich ein Label „Hello, World!“ zentriert in der Mitte des Bildschirms. Nun stellen wir in Xcode das Deployment-Target auf iOS 12.1.

Um die Auswirkungen der ABI-Stabilität zu testen stellt man in Xcode 10.2 das Deployment-Target auf iOS 12.1.

Dadurch ist Xcode gezwungen, zwei Binärdateien der App zu erzeugen. Eine, die noch alle benutzen Swift-Bibliotheken enthält (weil diese in iOS 12.1 noch nicht im Betriebssystem vorhanden sind) und eine weitere, die diese nicht mehr enthält (für Geräte mit iOS 12.2 oder höher). Doch da ergibt sich ein Problem, denn Xcode lädt stets eine spezielle Version der App in den App Store hoch, die sämtliche benötigten Bibliotheken enthält – unabhängig vom eingestellten Target. Sie werden erst dann wieder herausgenommen und auf das spezielle Gerät und das vorhandene Betriebssystem hin angepasst, wenn ein Anwender die App aus dem Store herunterlädt. Um das zu simulieren, kann man in Xcode eine so genannte „Development Distribution“ erzeugen, die auf ein ganz spezielles Gerät hin zugeschnitten ist. Diese Version wird nicht zu Apple in den Store hochgeladen, sondern stattdessen auf der Festplatte des Entwickler-Mac gespeichert. Wichtig ist, dass man das so genannte „App Thinning“ aktiviert, indem man im entsprechenden Pop-Up ein konkretes iOS-Gerät auswählt (in unserem Fall ein iPhone XS).

Xcode kann beim Export der App den App Store simulieren, dazu aktiviert man das „App Thinning“.

Nachdem Xcode den Quellcode compiliert und die App exportiert hat, schauen wir uns den Export-Ordner einmal genauer an. Tatsächlich finden sich zwei .ipa-Dateien (iOS-Apps haben stets die Endung „.ipa“) darin. Eine davon ist 2,4 MB (genau: 2.375.827 Bytes) groß, die andere lediglich 26 KB (genau: 25.540 Bytes). Das entspricht also einer Ersparnis von über 2,3 MB pro installierter App – im einfachsten Fall, denn unsere Demo-App benutzt ja kaum Funktionsbibliotheken. Im Normalfall dürfte die Einsparung noch größer ausfallen.

Geht man davon aus, dass man auf seinem iPhone typischerweise 100 Apps installiert hat, die in Swift programmiert wurden, summiert sich das schon auf ganz erkleckliche 230 MB auf. Na, das lohnt sich doch!

Das hat sich gelohnt: Eine fast leere App belegt nur noch 26 KB statt 2,4 MB auf dem iPhone!

Leider bekommt man diesen Speicherplatz nicht sofort zurück, indem man einfach iOS 12.2 installiert (wenn es einmal offiziell da ist). Die Entwickler müssen schließlich die Apps in Swift 5/Xcode 10.2 neu erzeugen und diese Versionen in den App Store hochladen. Man kann aber davon ausgehen, dass das in den nächsten Monaten sukzessive passieren wird. Freuen Sie sich also auf mehr freien Speicher im iPhone und iPad.

Es gibt noch jede Menge weitere Neuheiten in Swift 5 und Xcode 10.2. Einige davon sind durchaus interessant beziehungsweise wichtig.

Keine automatische Konvertierung mehr von Swift 3

Entwickler sollten aufpassen, denn ab Xcode 10.2 findet keine automatische Quellcode-Konvertierung von Swift 3 mehr statt. Wer seinen Code an Swift 5 anpassen will und noch die Swift-3-Synthax verwendet, sollte zunächst mit Xcode 10.1 auf Swift 4 umstellen und dann erst Xcode 10.2/Swift 5 einsetzen.

Raw-Strings

Wer viel mit String-Literals arbeitet, kennt das Problem:

Raw-Strings vereinfachen die Arbeit mit String-Literals

Diese Zeile geht schief, denn für Swift ist der String-Literal bei dem Anführungszeichen vor „Pangalaktischen ...“ zuende. Xcode wirft entsprechende Fehlermeldungen aus. Bislang konnte man sich hier mit Escape-Codes behelfen, ein Backslash vor jedem Anführungszeichen behebt das Problem:

Escape-Codes – wie hier ein Backslash vor jedem Anführungszeichen – sind schlecht lesbar und eine immerwährende Fehlerquelle

Das sieht aber unschön aus und ist auch schwerer zu lesen. Mit den neuen Raw-Strings kann man das nun so lösen:

Beim Einsatz von Raw-Strings bleibt der eigentliche String-Litreal unangetastet.

Ein Hashtag (auch Doppelkreuz genannt) vor und nach dem String-Literal verwandelt den gesamten String in einen Raw-String. Die Anführungszeichen im Literal werden also als Teil des Strings betrachtet. Das ist viel besser und die Raw-Strings lassen sich zudem auch mit String-Interpolationen verbinden.

Auch in Verbindung mit String-Interpolationen bringen Raw-Strings Vorteile.

Man beachte das Hashtag # vor „\(Antwort)“. Ohne diesen würde „\(Antwort)“ einfach zur Zeichenfolge des Raw-Strings zählen. Will man also, dass die String-Interpolation in einem Raw-String erfolgt, muss man das zusätzliche Hashtag # einfügen. Durch das Code-Coloring sieht man zudem sofort, wo im String-Literal eine String-Interpolation versteckt ist.

Ganzzahlen auf Vielfache überprüfen

Die neue Methode „isMultiple(of:) checkt ganzzahlige Variablen auf Vielfache. Das sieht zum Beispiel so aus:

Prüfen, ob eine Zahl gerade oder ungerade ist, geht mit der neuen Methode „isMultiple(of:) einfacher.

Hier prüfen wir eine Ganzahl, ob sie gerade oder ungerade ist. Gut, mit der altmodischen Variante, über Operator „Modulo 2“, also den Rest einer Division durch 2 auf Null zu prüfen, ginge das natürlich auch immer noch, aber das ist nicht so gut lesbar und die Methode „.isMultiple(of:)“ taucht in der Liste der Code-Completions auf. Damit findet man sie beim Programmieren schneller.

Neuer Standard-Ergebnisstyp „Results“

Besonders, wer Apps programmiert, die Daten asynchron aus dem Netz abrufen, wird diesen neuen Datentyp zu schätzen wissen. Der Result-Typ wird als Aufzählung (Datentyp: „enum“) mit zwei Fällen implementiert: Erfolg und Misserfolg. Beide werden mithilfe von Generics implementiert, sodass sie einen vom Entwickler gewünschten Wert haben können. Der Fehlerfall muss jedoch dem Swift-Fehlertyp entsprechen.

Der neue Result-Datentyp vereinfacht vor allem die Fehlerbehandlung, falls eine URL falsch ist, das Netz gerade nicht zur Verfügung steht oder die Abfrage zu lange dauert und die App in einen Timeout läuft. Bislang musste man diese Fälle einzeln mit komplizierten Fehlerabfragen („Try/Catch“-Strukturen) abfangen, nicht selten führte das zu unvorhersehbaren Problemen oder sogar zum Crash der App. Der neue Datentyp sorgt für mehr Sicherheit für den Anwender und weniger Aufwand beim Abfangen möglicher Fehler für den Entwickler

Dynamic Callables

Über Dynamic Callables lassen sich Datentypen, beispielsweise Strukturen genauso wie Funktionen aufrufen, also Methoden und Eigenschaften einfügen. Dabei ist es möglich den Instanzen dieser Datentypen eine variable Anzahl von Parametern zu übergeben. Für bestimmte Anwendungen kann das extrem hilfreich sein, dürfte aber sicher keine allzu große Verbreitung finden. Letztlich soll diese Funktion die Arbeit mit Swift neben dynamischen Sprachen wie Python und JavaScript erleichtern.

Ausblick, Swift 5.1 kommt bald

Die hier angesprochenen neuen Funktionen sind nur eine kleiner Ausschnitt aus der Liste der gesamten Neuerungen in Swift 5 und es wird weitergehen: Swift 5.1 ist bereits in der Mache. Auch hier wird es interessante Neuheiten geben. Nach der ABI-Stabilität steht nun die Modul-Stabilität an. Hier geht es um den genauen Aufbau der Funktionsbibliotheken. Auch der muss festgelegt werden, damit zukünftige Compiler beispielsweise für Swift 6 kompatibel zu bereits existierenden Bibliotheken bleiben und umgekehrt! Sobald Swift 5.1 finalisiert ist (das könnte noch im März 2019 passieren), werden wir uns an dieser Stelle wieder melden.

Fazit

Swift ist weiter in Bewegung. Es ist schön zu sehen, dass die Sprache nicht statisch auf der Stelle steht, sondern sich organisch weiterentwickelt und immer neue Funktionen und Möglichkeiten hinzugefügt werden. (Macwelt)