Swift 2.2

Voraussichtlich ist Swift 2.2 die letzte Swift-Version vor dem großen, für Herbst geplanten Update auf Swift 3. Swift 2.2 bietet im Vergleich zu Swift 2.0/2.1 einige neue Funktionen. Beim Design von Swift 2.2 war die Kompatibilität zu vorhandenem Swift-2-Code ein wichtiges Ziel. Die meisten Neuerungen sind als Ergänzungen/Erweiterungen konzipiert, die optional verwendet werden können, aber keinen Einfluss auf vorhandenen Code haben.

Dennoch zeigt Swift 2.2 bereits in einigen Punkten die Richtung an, in die sich Swift weiterentwickelt. So wurden diverse Sprachmerkmale von Swift als deprecated gekennzeichnet. Das betrifft z.B. klassische for-Schleifen, die in Swift 2.2 weiter ausgeführt werden, in Xcode aber als deprecated gekennzeichnet werden. Diese Kennzeichnung gibt Entwicklern die Möglichkeit, schon jetzt damit zu beginnen, ihren Code möglichst Swift-3-konform zu gestalten.

Diese Artikel fasst die Neuerungen auf der Basis von Xcode 7.3 Beta 5 zusammen. Ich werde den Text nach der Freigabe von Xcode 7.3 nochmals aktualisieren. Inzwischen ist Xcode 7.3 freigegeben. Es hat keine für diesen Artikel relevanten Änderungen mehr gegeben.

Lesen Sie auch die Zusammenfassung über den aktuellen Stand der Pläne für Swift 3!

Neu: Tupel-Vergleiche

Bis einschließlich Swift 2.1 können Tupel nicht verglichen werden. Swift 2.2 stellt für Tupel mit bis zu sechs Elementen die Operationen == und != zur Verfügung.

//: Tupel vergleichen (zulässig für Tupel mit bis zu sechs Elementen)
let tupel1 = (1, 2)
let tupel2 = (1, 2)
if tupel1 == tupel2 {
  print("Die beiden Tupel sind identisch.")
}

// das folgende Beispiel funktioniert nicht, weil die Tupel zu viele Elemente haben
let tupel3 = (1, 2, 3, 4, 5, 6, 7)
let tupel4 = (1, 2, 3, 4, 5, 6, 7)
if tupel3 == tupel4 {
  print("Die beiden Tupel sind identisch.")
}

Deprecated: Tupel Splat

Und weil wir schon bei Tupel sind: Die wenig bekannte Tuple-Splat-Syntax, die es erlaubt, ein Tupel mit n Elementen an eine Funktion/Methode mit ebenso vielen Parametern zu übergeben, gilt nun als deprecated und wird in Swift 3 ganz verschwinden. Der Grund: Der Code ist schwer zu lesen und stiftet Verwirrung. Der Aufruf g(tupel) sieht so aus, als würde an g nur ein Parameter übergeben.

func g(a a:Int, b:Int, c:Int) -> Int {
  return a+b+c
}
let tupel = (a:2, b:4, c:8)
print( g(tupel) )   // Ausgabe: 14

Deprecated: Inkrement- und Dekrement-Operator

Die Operatoren ++ und -- gelten als deprecated. In vielen Fällen können Sie i++ oder ++i einfach durch i+=1 ersetzen. Wenn Sie aber den bisherigen oder aktuellen Wert gleichzeitig an eine Funktion/Methode übergeben, dann müssen Sie Ihren Code umbauen:

// in Swift 2.2 deprecated, aber noch erlaubt
var x=3
while(x>0) {
  print(--x)
}

// Swift-3-kompatibler Code
var x=3
while(x>0) {
  x-=1
  print(x)
}

Deprecated: Die klassische for-Schleife

Die klassische, aus C vertraute for-Schleife wird in Swift 2.2 letztmalig akzeptiert. Die Entwickler argumentieren, dass sich der Code in den meisten Fällen eleganter formulieren lässt — und oft trifft dies auch zu, vor allem wenn die zu verarbeitenden Daten ohnedies bereits in Arrays, Sets oder anderen Aufzählungsklassen vorliegen. Bei anderen Aufgabenstellungen ist der Verzicht auf die klassische for-Schleife hingegen lästig und zwingt zu while-Schleifen oder anderen Konstrukten, die den Code in der Regel nicht besser lesbar machen. Insofern ist die Abschaffung der for-Schleife nicht vollständig nachvollziehbar.

Wie dem auch sei … Einfache Schleifen im Stil von for var i=start; i<end; i++ machen wenig Probleme und können mit for i in start..<end formuliert werden. Xcode unterstützt Sie dabei mit Fix-it-Vorschlägen.

// Swift 2.2: deprecated, aber OK
let max=3  // exklusive
for var i=0; i<max; i++ {
  print(i)
}

// Lösung für Swift 3
for i in 0 ..< max {
  print(i)
}

Schon schwieriger ist es, eine Schleife rückwärts zu durchlaufen:

// Swift 2.2: deprecated, aber OK
for var i = max-1; i>=0; i-=1 {
  print(i)
}

// Lösung für Swift 3
for i in (0..<max).reverse() {
  print(i)
}

// alternative Lösung für Swift 3
var i = max-1
while(i>=0) {
  print(i)
  i-=1
}

Schleifen mit Fließkommavariablen sind generell selten eine gute Idee. Höchste Zeit, den Code umzustellen!

// Swift-2.2-Code, +0.0001 wegen möglicher Rundungsfehler
for var x=0.0; x <= 2 * M_PI + 0.0001; x += M_PI/10 {
  print(x)
}
// besserer Code, Swift-3-kompatibel
for n in 0...20 {
  print(M_PI / 10.0 * Double(n))
}

Am allgemeingültigsten ist immer der Umbau von for nach while:

// in Swift 2.2 noch erlaubt
for var x=1.0; x<100; x*=1.3 {
  print(x)
}

// Swift-3-kompatibler Code
var x=1.0
while(x<100) {
  print(x)
  x*=1.3
}

Neu: typealias versus associatedtype

In Swift 2 hat das Schlüsselwort typealias zwei Bedeutungen: Einerseits wird es — seinem Namen entsprechend — verwendet, um einen Alias für einen vorhandenen Datentyp zu definieren. Andererseits dient es zur Deklaration von generischen Typen in Protokollen. Beginnend mit Swift 3 muss für diesen zweiten Fall das neue Schlüsselwort associatedtype verwendet werden:

// Swift-2-Code, wird in 2.2 mit deprecated-Warnung akzeptiert
protocol Generator {
  typealias Element
  mutating func next() -> Element?
}

// korrekter Swift-3-Code
protocol Generator {
  associatedtype Element
  mutating func next() -> Element?
}

// noch logischer wäre meiner Ansicht nach
// protocol Generator<Element> { ... }
// diese Syntax ist aber weder in Swift 2 noch in Swift 3 zulässig

Neue Selektor-Syntax

Momentan müssen Referenzen auf Methoden (action-Parameter) in der Objective-C-Syntax als Zeichenketten angegeben werden. Der Swift-Compiler kann diese Zeichenkette nicht verifizieren. Bei Tipp- oder Syntaxfehlern tritt zu Laufzeit ein Fehler auf. In Swift 2.2 kann der Selektor in der Form #selector(Klasse.methode) bzw. #selector(Klasse.methode(parameter ...)) definiert werden. Ab Swift 3.0 ist diese Syntax zwingend. Das folgende Beispiel illustriert die Syntax. Xcode hilft bei der Umwandlung mit Fix-its.

// deprecated ab Swift 2.2
btn.addTarget(self,
  action: "buttonAction:",
  forControlEvents: .TouchUpInside)

// erlaubt ab Swift 2.2, erforderlich ab Swift 3
btn.addTarget(self,
  action: #selector(ViewController.buttonAction(_:)),
  forControlEvents: .TouchUpInside)

Neu: Code-Zweige für verschiedene Swift-Versionen

Sie können in den Swift-Code nun verschiedene Zweige einbauen, die je nach Swift-Version berücksichtigt bzw. ignoriert werden:

#if swift(>=3)
  print("Ein Blick in die Zukunft")
#else
  print("Noch mit Swift 2.n unterwegs")
#endif

Neu: Schlüsselwörter als Parameternamen

Die meisten Swift-Schlüsselwörter dürfen ab Swift 2.2 als Parameternamen verwendet werden. Insbesondere ist nun in als Parametername erlaubt. Innerhalb der Funktion müssen derartige Parameternamen in nach rechts gerichtete Apostrophe (Backticks) gestellt werden.

func f(in in:Int, inout out:Int) {
  out = `in` * 2
}
var x:Int = 0
f(in:2, out: &x)
print(x)  // Ausgabe 4

Deprecated: var-Parameter

Parameter von Funktionen und Methoden können momentan mit dem zusätzlichen Schlüsselwort var gekennzeichnet werden. Das bedeutet, dass diese Parameter innerhalb der Funktion/Methode verändert werden darf. Die Veränderung gilt allerdings nur innerhalb der Funktion/Methode, nicht aber nach außen hin. Das ist selten zweckmäßig und stiftet außerdem eine Menge Konfusion mit dem im vorigen Beispiel eingesetzten Schlüsselwort inout, das zur Deklaration von Referenz-Parametern dient. inout wird es weiterhin geben, aber var-Parameter gelten beginnend mit Swift 2.2 als deprecated und werden in Swift 3 ganz verschwinden.

// var-Parameter sind jetzt deprecated und ab Swift 3 nicht mehr zulässig
func h(var a:Int) {
  a+=1
  print(a)
}
h(3)  // Ausgabe 4

Sonstiges

  • removeFirst(): Für Arrays und andere Datentypen, die das Protokoll RangeReplaceableCollectionType implementieren, gibt es jetzt auch die praktische Methode removeFirst. (removeLast gab es ja schon immer.)

  • Neue Schlüsselwörter in Markdown-Kommentaren: In Markdown-Kommentaren konnten Sie schon bisher Schlüsselwörter wie parameter name:, returns: und throws: verwenden, um die Parameter eine Methode/Funktion zu dokumentieren, den Rückgabewert zu beschreiben oder auf mögliche Fehler hinzuweisen. Zu diesen Schlüsselwörtern kommen nun keyword:, recommended: und recommendedover: hinzu.

  • Naming Functions with Argument Labels: Schon bisher konnten Sie Funktionen/Methoden als Referenz übergeben oder in einer Variablen speichern (let myfunc = someView.insertSubview). Diese Syntax ist aber problematisch, wenn es mehrere gleichnamige Varianten der Funktion/Methode gibt, die sich nur durch die Parameterliste unterscheiden. Neu in Swift 2.2 ist die Möglichkeit, nun auch die Parameter anzugeben um so klar zu machen, welche Variante Sie meinen: let myfunc = someView.insertSubview(_:aboveSubview:)

  • Constraining AnySequence.init: Die init-Funktion von AnySequence hat sich geändert. Wenn Sie eigene Klassen von AnySequence abgeleitet haben, müssen Sie gegebenenfalls deren init-Code anpassen.

  • getDemangledTypeName: Die nie dokumentierte Funktion _stdlib_getDemangledTypeName ist verschwunden. Den Typ einer Instanz ermitteln Sie am besten mit String(obj.dynamicType). Die Ergebnisse sind allerdings nicht immer exakt dieselben. Beispielsweise lieferte _stdlib_getDemangledTypeName den Typnamen NSDate, während String(mydate.dynamicType) die Zeichenkette __NSDate zurückgibt.

  • #file, #line etc.: Im Programmcode können Sie mit __FILE__, __LINE__ etc. auf den Dateinamen, die aktuelle Zeile etc. zugreifen, z.B. um diese Daten in Debug-Code zu integrieren. Diese Schreibweise gilt nun als deprecated. Neu und optisch weit weniger aufdringlich ist die neue Syntax #file, #line, #column, #function. Beispiel: let fname = #file oder let linenr = #line.

Geplant, aber noch nicht implementiert

Neuerungen im Playground

Die Gestaltungs- und Steuerungsmöglichkeiten in Playgrounds werden weiter aufgewertet, vermutlich, damit diese Dokumente sich noch besser zum Einsatz für Dokumentation und Unterricht eignen. So können nun auch Videos eingebettet werden, sofern diese zuvor den Ressourcen des Playgrounds hinzugefügt wurden.

![Beschriftung](filename.mp4 width="640" height="480" poster="vorschaubild.png")

Mit gewissen Einschränkungen sind in Playgrounds nun Live-Interaktionen mit per Playground-Code erzeugten iOS- oder OS-X-Steuerelementen erlaubt.

Hinter den Kulissen wurde die Interna der Playground-Darstellung verändert. Das ist unter anderem daran erkennbar, dass Markdown-Kommentare jetzt einer anderen Schrift angezeigt werden.

Unverändert läuft Code in Playgrounds relativ langsam. Bei der Eingabe neuen Codes kommt es immer wieder zu Problemen. Bei meinen Tests brach die Kommunikation zwischen dem Playground und dem Swift-Compiler immer wieder ab (failed to launch stub for playground execution). Manchmal gelingt die Wiederaufnahme der Kommunikation, andernfalls ist ein Neustart von Xcode notwendig.

Beispieldateien zu meinem Swift-2-Buch

Alle Beispieldateien meines Swift-2-Buchs liegen nun auch in einer überarbeiteten Fassung für Swift 2.2 vor. Die Beispiele sind nun frei von deprecated-Warnungen. Die Top-Drei der Änderungen waren: for-Schleifen, x++/x-- sowie Selektoren. Insgesamt war der Umbau aller Beispiele in ca. einem halben Tag erledigt.

Beispieldateien Swift 2.2 (ZIP)

Quellen

Implementierte oder geplante Proposals für Swift 2.2

dynamicType und getDemangledTypeName