Swift 3.0 ist fertig. Seit 7. September 2016 ist Xcode 8 als Gold Master (GM) für alle Teilnehmer des Apple-Developer-Programms verfügbar, in ein paar Tagen wird die finale Version kostenlos im App Store auftauchen. Was ist also neu?
Updates 17.9.2016, 20.9.2016: Noch mehr Details sowie Xcode-Screenshots.
98 realisierte Detailveränderungen
Der Entwicklungsprozess von Swift 3.0 ist öffentlich verlaufen. Daher sind die geplanten und tatsächlich durchgeführten Änderungen schon seit Monaten bekannt (siehe auch Pläne für Swift 3). Eine vollständige, wenn auch nicht gerade lesefreundliche Zusammenstellung aller Neuerungen finden Sie in dieser Liste:
http://apple.github.io/swift-evolution
Diese Liste fasst alle in Form offizieller Proposals eingereichter Änderungswünsche zusammen. Aus verschiedenen Gründen wurden nicht alle Ideen tatsächlich realisiert. Der für Swift 3.0 relevante Teil beginnt bei der Überschrift Implemented for Swift 3. Das sind 90 Punkte. Dazu kommen acht Vorschläge, die bereits in Swift 2.2 realisiert wurden — macht also, wenn man Swift 2.1 als Maßstab nimmt, 98 Änderungen von Swift 2.n zu Swift 3.0.
Eine kompakte Zusammenstellung der wichtigsten Änderungen bieten darüber hinaus die Release Notes, die aktuell nur für Apple-Developer-Mitglieder zugänglich sind.
Außerdem wurde das von Apple verfasste Swift-Handbuch auf Swift 3 adaptiert.
An Lesestoff scheitert es also nicht …
Die Spreu vom Weizen trennen
98 Änderungen klingt dramatisch — aber zum Teil handelt es sich um Kleinigkeiten (z.B. die Umbenennung von flatten
in joined
, Proposal 0133), zum Teil um die Verfeinerung bzw. um die exakte Formulierung von Syntaxfeinheiten (z.B. der Umgang mit Enumerations-Elementen, Proposal 0036). Deswegen möchte ich mich in den weiteren Abschnitten auf meine persönlichen Favoriten unter den Swift-3-Neuerungen konzentrieren.
Swift-freundlichere Bibliotheken
Die für App-Entwickler wichtigste Neuerung hat gar nicht mit der Swift-Syntax an sich zu tun, sondern vielmehr mit der Schnittstelle zu den vielen, teilweise schon seit Jahren verfügbaren Bibliotheken (Cocoa, UIKit, Foundation usw.). Diese Bibliotheken wurden allesamt für Objective C entwickelt. Die Nutzung der dort definierten Klassen, der Aufruf der Methoden erwies sich in Swift als umständlich und ganz und gar unswifty.
Nun kann selbst Apple nicht alle Bibliotheken neu schreiben. Stattdessen hat man sich dazu entschlossen, parallel zur Objective-C-Schnittstelle eine zweite Swift-Schnittstelle zu den Bibliotheken zu schaffen, die den Gepflogenheiten von Swift besser entspricht und die zu klarerem und oft auch etwas kürzerem Code führt.
Einige Beispiele, immer zuerst in der Swift-2- und dann in der Swift-3-Version:
NSUserDefaults.standardUserDefaults() -->
UserDefaults.standard
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) -->
func prepare(for segue: UIStoryboardSegue, sender: Any?)
let dest = segue.destinationViewController -->
let dest = segue.destination
txt.stringByTrimmingCharactersInSet(
NSCharacterSet.whitespaceAndNewlineCharacterSet()) -->
txt.trimmingCharacters(in: .whitespacesAndNewlines)
Außerdem wurden viele Klassen der Foundation-Bibliothek umbenannt, z.B.:
NSBundle --> Bundle
NSDate --> Date
NSFileManager --> FileManager
NSFormatter --> Formatter
NSLocal --> Locale
NSNumberFormatter --> NumberFormatter
NSTask --> Process (!!)
NSThread --> Thread
NSURL --> URL
NSURlxxx --> URLxxx
Schließlich wurden viele Swift-eigene Klassen der Standard Library optimiert, insbesondere was den Umgang mit Aufzählungen (Sequences) betrifft.
Basis für diese Anpassungen waren die folgenden Proposals:
- Proposal 0005, Better Translation of Objective-C APIs Into Swift
- Proposal 0006, Apply API Guidelines to the Standard Library
- Proposal 0023, API Design Guidelines (unbedingt lesen!)
- Proposal 0033, Import Objective-C Constants as Swift Types
- Proposal 0045, Add prefix(while:) and drop(while:) to the stdlib
- Proposal 0065, A New Model for Collections and Indices
- Proposal 0086, Drop NS Prefix in Swift Foundation
- Proposal 0088, Modernize libdispatch for Swift 3 naming conventions
- Proposal 0094, Add sequence(first:next:) and sequence(state:next:)
- Proposal 0118, Closure Parameter Names and Labels
- Proposal 0133, Rename flatten() to joined()
Konsistenter Umgang mit den Parametern von Methoden, Funktionen und Attributen
Ein Relikt aus Objective-C-Zeiten war Swifts Umgang mit den Parametern von (Init)-Funktionen, Methoden und Attributen. Mal war der erste Parameter automatisch unbenannt, dann wieder nicht. Noch chaotischer wäre es kaum gegangen.
Mit Swift 3 ist damit Schluss. Es gelten nun für alle Parameter dieselben Regeln. Außerdem wurden einige syntaktische Feinheiten geklärt bzw. vereinfacht. Das betrifft z.B. die Reihenfolge, in der Default-Parameter übergeben werden müssen, sowie den Umgang mit inout
-, var
– und let
-Parametern. Das folgende Listing gibt einen Überblick über die aktuelle Syntax zur Deklaration von Paramtern:
func f() { ... } // kein Parameter
func f(para: Int) { ... } // gewöhnlicher Parameter
func f(_ para: Int) { ... } // unbenannter Parameter
func f(ext para: Int) { ... } // zweinamiger Parameter
func f(para: inout Int) { ... } // veränderlicher Parameter
func f(_ para: inout Int) { ... } // unbenannter ver. Parameter
func f(ext para: inout Int) { ... } // zweinamiger ver. Parameter
func f(para: Int = 0) { ... } // optionaler Parameter
func f(_ para: Int = 0) { ... } // unbenannter opt. Parameter
func f(ext para: Int = 0) { ... } // zweinamiger opt. Parameter
func f(para: Int ...) { ... } // variadischer Parameter
func f(_ para: Int ...) { ... } // unbenannter var. Parameter
func f(ext para: Int ...) { ... } // zweinamiger var. Parameter
Die Konzepte aller Änderungen sind hier zusammengefasst:
- Proposal 0002, Removing currying func declaration syntax
- Proposal 0003, Removing var from Function Parameters
- Proposal 0031, Adjusting inout Declarations for Type Decoration
- Proposal 0035, Limiting inout capture to @noescape contexts
- Proposal 0040, Replacing Equal Signs with Colons For Attribute Arguments
- Proposal 0046, Establish consistent label behavior across all parameters including first labels
- Proposal 0047, Defaulting non-Void functions so they warn on unused results
- Proposal 0049, Move @noescape and @autoclosure to be type attributes
- Proposal 0053, Remove explicit use of let from Function Parameters
- Proposal 0060, Enforcing order of defaulted parameters
- Proposal 0066, Standardize function type argument syntax to require parentheses
- Proposal 0103, Make non-escaping closures the default
Generics
Apple hat große Pläne, was die Optimierung der generischen Funktionen in Swift anbelangt. Von diesen Plänen ist bisher aber nur ein Teil realisiert. So gibt es jetzt generische Typen-Aliase, where
-Bedingungen für generische Parameter werden lesbarer formuliert, generische Protokolle klarer formuliert.
// generische Typ-Aliase
typealias StringDictionary<T> = Dictionary<String, T>
typealias IntFunction<T> = (T) -> Int
typealias MatchingTriple<T> = (T, T, T)
typealias BackwardTriple<T1,T2,T3> = (T3, T2, T1)
// Position von 'where' nach Parameterliste und Rückgabetyp
func toArray<S: Sequence, T> (_ seq : S) -> [T]
where T == S.Iterator.Element
{ ... }
// generische Protokolle mit »associatedtype«
protocol Generator {
associatedtype Element // statt bisher: typealias Element
mutating func next() -> Element?
}
- Proposal 0011, Replace typealias keyword with associatedtype for associated type declarations (gilt schon seit Swift 2.2)
- Proposal 0048, Generic Type Aliases
- Proposal 0061, Generic Result and Error Handling
- Proposal 0081, Move where clause to end of declaration
- Proposal 0095, Replace protocol<P1,P2> syntax with P1 & P2 syntax
Sonstige Neuerungen
Swift hat das Overloading bzw. die Neudefinition von Operatoren schon in der ersten Version sehr leicht gemacht. Jetzt gibt es eine neue Syntax, um die Priorität neuer Operatoren besser zu definieren. Sehr nett.
Bisher konnten öffentliche Klassen (public
) gleichermaßen verwendet und abgeleitet werden. Wer seine Klasse als public
deklarierte, erlaubt also nicht nur die Nutzung der Klasse, sondern auch ihre Verwendung als Basis für eigene, abgeleitete Klassen. In Zukunft erlaubt public
nur die Nutzung der Klasse. Ist die Klasse auch als Basis für andere, vererbte Klassen vorgesehen, muss sie als open
deklariert werden. Analog bedeutet public
bei Methoden, dass die Methode aufgerufen werden kann. Darf die Methode auch überschrieben (überladen) werden, muss sie mit open
deklariert werden.
Insgesamt gibt es jetzt fünf Schlüsselwörter zur Zugriffssteuerung, deren Bedeutung im folgenden Listing kurz skizziert ist:
open // Zugriff und Vererbung in anderen Modulen
public // Zugriff auch in anderen Modulen,
// aber Vererbung nur im eigenen Modul
internal // Zugriff und Vererbung nur im eigenen Modul
fileprivate // Zugriff und Vererbung nur in der aktuellen Datei
private // Zugriff nur in der aktuellen Klasse
- Proposal 0025, Scoped Access Level
- Proposal 0117, Allow distinguishing between public access and public overridability
Nicht so toll
Nicht alle Neuerungen sind aus meiner Sicht Verbesserungen. Mit der Abschaffung der Operatoren ++
und --
kann ich persönlich gut leben. x+=1
ist für mich in der Regel gut genug.
Aber dass die klassische for
-Schleife eliminiert wurde, finde ich einfach nur idiotisch. Hier hat der Wahnsinn Methode. Das Argument, for
-Schleifen wären schwer zu lesen oder unswifty, ist einfach absurd — nahezu jede andere Programmiersprache hat solche Schleifen, jeder Programmierer, jede Programmiererin lernt den Umgang mit solchen Schleifen in der ersten oder zweiten Stunde.
Natürlich gibt es viele Fälle, wo for
-Schleifen in Swift unkompliziert mit for-in
nachgebildet werden können (for i in 1...3
, for item in myArray
). Aber in allen anderen Fällen sind nun wesentlich umständlichere Konstruktionen mit while
, stride
oder reversed
notwendig. Klarerer, effizienterer Code resultiert daraus eher selten.
Hier sind die durchaus heiß diskutierten Proposals:
In der Motivation schon eher verständlich, in der Auswirkungen aber auch nicht immer toll, ist die Abschaffung impliziter (automatischer) Typumwandlungen zwischen Swift-Typen und Objective-C-Typen. Swift war bei Typumwandlungen schon bisher restriktiv, jetzt wird es noch schlimmer. Keine Zeile ohne Casting. (Na ja, ich übertreibe mal wieder …)
Xcode 8
Die größte Neuerung von Xcode 8 besteht natürlich in der Unterstützung von Swift 3. Aber es gibt noch mehr Verbesserungen :-)
- Im Storyboard-Editor können Sie nun in beliebigen Zoom-Stufen arbeiten.
-
Bei iOS-Apps können Sie direkt im Storyboard-Editor die Views blitzschnell zwischen verschiedenen iOS-Geräten sowie zwischen Hoch- und Querformat umstellen. Kein umständliches Hantieren mit der Preview-Ansicht, keine quadratischen Views mehr. Sehr gut.
-
Farben und Bitmaps aus Xcassets-Dateien können im Code als Literale eingebaut werden. Diese Literale zeigen die Farbe bzw. eine winzige Vorschau der Bitmap. Eine Kleinigkeit, aber ungemein praktisch!
-
Der Code-Konverter, der Ihre Projekte von Swift 2 auf Swift 3 umstellt, funktioniert größtenteils sehr gut. Besonders schnell gelingt der Umstieg, wenn Sie Ihren Code zuvor schon an Swift 2.2 angepasst haben.
-
Das Signing wurde verbessert. Zum einen kann Xcode nun auf mehreren Rechnern einen Developer Account nutzen, ohne dass es Konflikte gibt. Zum anderen löst das neue Auto Signing viele Probleme. Insbesondere ist es beim Einreichen einer App nicht mehr notwendig, Distribution Provisioning Profiles manuell einzurichten — Xcode kann das jetzt automatisch.
Ärgerlich finde ich, dass es immer noch keine Refactoring-Unterstützung für Swift gibt. Gerade die ständigen Umbauten an Swift machen oft auch umfassende Änderungen im eigenen Code notwendig. Da könnte Xcode gerne ein wenig mithelfen.
Die Stabilität von Xcode ist aus meiner Sicht OK, aber hier kann sicher noch gefeilt werden. Richtige Abstürze habe ich bisher keine bemerkt, aber dass der Playground den Kontakt zum Compiler verliert, passiert ständig. Etwas seltener geschieht dies in richtigen Projekten — plötzlich funktioniert die Auto-Vervollständigung nicht mehr.
Ein weiteres Ärgernis alter Xcode-Versionen wartet auf Behebung: Bereits behobenen Syntaxfehler werden weiter als Fehler gekennzeichnet, bis mit cmd+B oder cmd+R ein neuerliches Kompilieren erzwungen wird. Hoffen wir also auf ein baldiges Xcode 8.0.1.
Swift-3-Buch
Die umfassende Berichterstattung über Swift 3 in diesem Blog hat natürlich damit zu tun, dass ich seit Monaten intensiv(st) an der Neuauflage meines Swift-Buchs arbeite. Ein paar Details kann ich schon verraten:
- Das Buch geht naturgemäß auf alle Neuerungen von Swift 3 ein.
- Es berücksichtigt neben iOS und macOS auch tvOS.
- Ein weiterer neuer Schwerpunkt ist SpriteKit (2D-Spiele-Programmierung mit mehreren Beispielen inklusive einem Pac-Man-Clone).
- Das Buch ist vollkommen neu in kleinere Kapitel strukturiert. Ich habe mich bemüht, das Buch in einer Art Baukasten-Konzept zusammenzusetzen, so dass die Kapitel möglichst unabhängig voneinander sind. Auch sind alle großen Beispiele nun von den Grundlagenkapiteln getrennt.
- Der Umfang wird auf vorauss. knapp 1200 Seiten anwachsen.
- Der Erscheinungstermin ist vorauss. Ende November.
Hallo, ich habe gerade mal auf swift.io nachgesehen und leider wird immer noch ausschließlich Ubuntu unterstützt. Weißt Du evtl. mehr? Gibt es Pläne, Swift auch auf anderen Distris zu portieren? Oder geht das gar schon und ich hab’s nur nicht gefunden?
Es gibt ja den Quellcode, d.h. wer will, kann es sich selbst kompilieren.
Persönlich habe ich auch den Eindruck, dass das Linux-Engagement Apples momentan sehr halbherzig ist. Auch die Ubuntu-Unterstützung ist ja mager, wen interessiert Swift für 15.10? Warum keine Paketquellen? Eine für Debian/Ubuntu, eine für Red Hat / Fedora …
Die besten Infos zu Swift und Linux gibts aktuell auf http://dev.iachieved.it. Siehe insbesondere:
http://dev.iachieved.it/iachievedit/swift-3-0-for-ubuntu-16-04-xenial-xerus