
Swift 5.0 wurde mit der Veröffentlichung von Xcode 10.2 verfügbar, aber die Arbeit an der nächsten Version geht weiter und es gibt bereits Neuigkeiten darüber, was Sie darin erwarten können.
Ein wichtiges Merkmal von
Swift 5.1 ist die
Modulstabilität , mit der wir Bibliotheken von Drittanbietern verwenden können, ohne uns Gedanken darüber machen zu müssen, mit welcher Version des Swift-Compilers sie erstellt wurden. Es sieht aus wie die
ABI-Stabilität, die wir in Swift 5.0 erhalten haben, aber es gibt einen kleinen Unterschied: Die ABI-Stabilität behebt Unterschiede in Swift-Versionen zur Laufzeit und Modulstabilität zur Kompilierungszeit.
Zusätzlich zu dieser wichtigen Innovation werden wir einige wichtige Verbesserungen in Swift erhalten, und in diesem Artikel werden wir sie mit Beispielen behandeln, damit Sie sie in Aktion sehen können.
Universelles Selbst
SE-0068 erweitert die Verwendung von
Self , sodass es sich auf den Typ bezieht, der es in Klassen, Strukturen und Aufzählungen enthält. Dies ist normalerweise für dynamische Typen nützlich, wenn zur Laufzeit der genaue Typ von etwas bestimmt werden muss.
Betrachten Sie als Beispiel den folgenden Code:
class NetworkManager { class var maximumActiveRequests: Int { return 4 } func printDebugData() { print("Maximum network requests: \(NetworkManager.maximumActiveRequests).") } }
Hier definieren wir die statische Eigenschaft
maximumActiveRequests innerhalb der
NetworkManager- Klasse und fügen die
printDebugData () -Methode hinzu, um diese Eigenschaft zu drucken. Hier ist alles in Ordnung, aber nur bis wir uns entscheiden, von
NetworkManager zu erben:
class ThrottledNetworkManager: NetworkManager { override class var maximumActiveRequests: Int { return 1 } }
In diesem Erben ändern wir die Eigenschaft maximumActiveRequests so, dass sie jetzt gleich eins wird. Wenn wir jedoch
printDebugData () aufrufen, wird
der Wert aus der übergeordneten Klasse abgeleitet:
let manager = ThrottledNetworkManager() manager.printDebugData()
Hier sollten wir 1 statt 4 bekommen, und hier kommt zur Rettung SE-0068: Wir können
Self (mit dem Großbuchstaben 'S') verwenden , um auf den aktuellen Typ zu verweisen. Jetzt können wir die
printDebugData () -Methode der übergeordneten Klasse folgendermaßen umschreiben:
class ImprovedNetworkManager { class var maximumActiveRequests: Int { return 4 } func printDebugData() { print("Maximum network requests: \(Self.maximumActiveRequests).") } }
Das heißt,
Self funktioniert genauso wie in Protokollen in früheren Versionen von Swift.
Warnungen vor Mehrdeutigkeit keine
Optionen in Swift werden als Aufzählung mit zwei Optionen implementiert:
einige und
keine . Dies kann zu Verwirrung führen, wenn wir eine eigene Aufzählung mit der Option
none erstellen und diese
optional einschließen . Zum Beispiel:
enum BorderStyle { case none case solid(thickness: Int) }
Bei Verwendung von nicht optional ist alles sauber:
let border1: BorderStyle = .none print(border1)
Dies gibt "keine" aus. Wenn wir für diese Aufzählung optional verwenden, stoßen wir auf ein Problem:
let border2: BorderStyle? = .none print(border2)
Hier wird Nil gedruckt, da Swift glaubt, dass .none bedeutet, dass optional
leer ist , obwohl es
mit einem Wert von BorderStyle.none tatsächlich optional ist.
In Swift 5.1 wird bei einer solchen Mehrdeutigkeit eine Warnung angezeigt:
„Angenommen, Sie meinen‚ Optional.none '; Meinten Sie stattdessen "BorderStyle.none"? "
Somit wird der Entwickler informiert, dass mit seinem Code nicht alles glatt sein kann.
Übereinstimmende optionale und nicht optionale Aufzählungen
Swift ist klug genug, um das switch / case-Konstrukt zu verstehen, wenn optionaler / nicht optionaler Text und ganzzahlige Werte kombiniert werden, nicht jedoch bei Aufzählungen.
Jetzt können wir in Swift 5.1 switch / case verwenden, um die optionalen und nicht optionalen Optionen für die Aufzählung abzugleichen:
enum BuildStatus { case starting case inProgress case complete } let status: BuildStatus? = .inProgress switch status { case .inProgress: print("Build is starting…") case .complete: print("Build is complete!") default: print("Some other build status") }
Swift kann optionale Aufzählungen nicht optionalen Optionen zuordnen. Hier wird "Build wird gestartet ..." angezeigt.
Vergleichen Sie geordnete Sammlungen
Mit SE-0240 wurde die Möglichkeit eingeführt, Unterschiede zwischen geordneten Sammlungen zu berechnen und das resultierende Vergleichsergebnis auf Sammlungen anzuwenden. Dies kann für Entwickler von Interesse sein, die komplexe Sammlungen in einer Tabellenansicht haben und mithilfe von Animationen viele Elemente hinzufügen oder entfernen müssen.
Das Grundprinzip ist einfach: Swift 5.1 bietet einen neuen Methodenunterschied
(von :) , der die Unterschiede zwischen zwei geordneten Sammlungen bestimmt - welche Elemente hinzugefügt und welche entfernt werden sollen. Dies gilt für alle bestellten Sammlungen, die Artikel enthalten, die dem
Equatable- Protokoll entsprechen.
Um dies zu demonstrieren, erstellen wir zwei Wertearrays, berechnen die Unterschiede voneinander und gehen dann die Liste der Unterschiede durch und wenden sie an, um die beiden Sammlungen gleich zu machen.
Hinweis: Da Swift jetzt als Teil der Apple-Betriebssysteme vertrieben wird, sollten neue Sprachtools mit der Prüfung
#available verwendet werden , um sicherzustellen, dass der Code auf einem Betriebssystem ausgeführt wird, das die erforderlichen Funktionen unterstützt. Für Funktionen, die auf unbekannten, unangekündigten Betriebssystemen ausgeführt werden, die möglicherweise in Zukunft veröffentlicht werden, wird die spezielle Versionsnummer "9999" verwendet. Dies bedeutet: "Wir kennen die richtige Versionsnummer noch nicht".
var scores1 = [100, 91, 95, 98, 100] let scores2 = [100, 98, 95, 91, 100] if #available(iOS 9999, *) { let diff = scores2.difference(from: scores1) for change in diff { switch change { case .remove(let offset, _, _): scores1.remove(at: offset) case .insert(let offset, let element, _): scores1.insert(element, at: offset) } } print(scores1) }
Für eine erweiterte Animation können wir den dritten Parameter in der resultierenden Liste der Unterschiede verwenden:
AssociatedWith . Anstelle von
.insert (let offset, let element, _) können wir also .insert schreiben (let offset, let element,
let relatedWith). Dies gibt uns die Möglichkeit, gleichzeitig Änderungspaare zu verfolgen: Wenn Sie das Element in der Sammlung um zwei Positionen nach unten verschieben, wird das Element gelöscht und dann hinzugefügt. Mit "verknüpft" diese beiden Änderungen und können diese Bewegung berücksichtigen.
Anstatt die Unterschiede einzeln manuell anzuwenden, können Sie sie mit der neuen Methode apply
() auf einen Schlag
anwenden :
if #available(iOS 9999, *) { let diff = scores2.difference(from: scores1) let result = scores1.applying(diff) ?? [] }
Nicht initialisierte Arrays erstellen
SE-0245 hat einen neuen Initialisierer für Arrays eingeführt, der ihn nicht mit Standardwerten füllt. Es war früher als private API verfügbar, was bedeutete, dass Xcode es nicht zur Vervollständigung des Codes aufforderte, aber Sie konnten es verwenden, wenn Sie es brauchten, und Sie haben das Risiko verstanden, dass diese Funktionalität möglicherweise nicht in der Zukunft verfügbar sein wird.
Um den Initialisierer zu verwenden, legen Sie die Größe des Arrays fest und übergeben Sie den Abschluss, der das Array mit Werten füllt. Ein Abschluss erhält einen unsicheren Zeiger auf einen veränderlichen Puffer sowie einen zweiten Parameter, in dem Sie angeben, wie viele Werte Sie tatsächlich verwenden.
Zum Beispiel können wir ein Array von 10 zufälligen ganzen Zahlen wie folgt erstellen:
let randomNumbers = Array<Int>(_unsafeUninitializedCapacity: 10) { buffer, initializedCount in for x in 0..<10 { buffer[x] = Int.random(in: 0...10) } initializedCount = 10 }
Es gibt verschiedene Regeln:
- Sie müssen nicht das gesamte von Ihnen angeforderte Volume verwenden, können es jedoch nicht überschreiten. Wenn Sie also die Größe des Arrays auf 10 festlegen, können Sie initializedCount im Bereich von 0 bis 10, jedoch nicht 11 festlegen.
- Wenn Sie beispielsweise die im Array verwendeten Elemente nicht initialisiert haben, initializedCount auf 5 gesetzt haben, die Elemente 0 bis 4 jedoch nicht mit echten Werten versehen haben, erhalten sie höchstwahrscheinlich zufällige Werte. Wie Sie wissen, ist dies eine schlechte Option.
- Wenn Sie initializedCount nicht festlegen, ist es gleich 0 und alle von Ihnen zugewiesenen Daten gehen verloren.
Ja, wir könnten den Code mit
map () umschreiben:
let randomNumbers2 = (0...9).map { _ in Int.random(in: 0...10) }
Dies ist offensichtlich besser lesbar, aber nicht so effektiv: Wir erstellen einen Bereich, dann ein neues leeres Array, weisen ihm eine Größe zu und „durchlaufen“ den gesamten Bereich, wobei wir jedem Element einen Abschluss zuweisen.
Fazit
Swift 5.1 befindet sich noch in der Entwicklung, und obwohl der letzte Zweig für Swift selbst abgeschlossen ist, sind Änderungen gegenüber einigen anderen verwandten Projekten noch sichtbar.
Die wichtigste Änderung ist also die
Modulstabilität , und es ist bekannt, dass das Entwicklungsteam hart daran arbeitet. Sie gaben kein genaues Veröffentlichungsdatum an, obwohl sie sagten, dass Swift 5.1 eine deutlich kürzere Entwicklungszeit hatte als Swift 5.0, was eine außergewöhnliche Konzentration an Energie und Aufmerksamkeit erforderte. Wir können den Zugriff auf WWDC19 annehmen, aber es ist offensichtlich, dass dies nicht der Fall ist, wenn Sie zu einem bestimmten Datum eilen müssen.
Ein weiterer Punkt, der Aufmerksamkeit verdient. Zwei Änderungen in dieser Liste („Warnungen bei Mehrdeutigkeit der Option none“ und „Übereinstimmende optionale und nicht optionale Aufzählungen“) waren nicht das Ergebnis der Swift-Entwicklung, wurden jedoch als Fehler erkannt und angepasst.