Was ist neu in Swift 5?

Hallo, ich heiße Ilya. Ich bin ein iOS-Entwickler bei Tinkoff.ru. In diesem Artikel werde ich einen kurzen Überblick über die wichtigsten Änderungen in Swift 5 geben. Diese Änderungen werden in den Versionshinweisen beschrieben . Für diejenigen, die sich noch nicht vertraut gemacht haben, willkommen bei cat!



Die Größe der Anwendung wird verringert!


In Swift 5 geschriebene und für iOS 12.2, watchOS 5.2, tvOS 12.2 kompilierte Anwendungen enthalten keine dynamischen Bibliotheken für die Swift-Standardbibliothek und das Swift SDK. Dies bedeutet, dass die Größe der Anwendung jedoch nicht wesentlich abnimmt. Wenn Sie diesem Tweet glauben, wurde die Größe des leeren Projekts von 2,4 MB auf 24 KB reduziert. Ein gutes Ergebnis für kleine Anwendungen, aber für große Anwendungen gibt es keinen großen Unterschied.

@dynamicCallable ( SE-0216 )


Mit dem Attribut @dynamicCallable können Sie mit einem Objekt als Funktion arbeiten. Solche Objekte werden Funktionsobjekte oder Funktoren genannt (weitere Details finden Sie hier ). Funktionale Objekte befinden sich in C ++, Python, JavaScript und anderen Sprachen. In Swift wurden sie hinzugefügt, um die Kompatibilität mit diesen Sprachen zu gewährleisten. Tatsache ist, dass Swift jetzt gut mit API C und Objective-C interagiert und Sprachentwickler die Interaktion mit dynamischen Sprachen hinzufügen möchten - Python, JavaScript, Ruby und anderen.

Um einen Typ zu einem Funktor zu machen, müssen Sie das Attribut @dynamicCallable zu seiner Deklaration hinzufügen. Stellen Sie sich ein Beispiel für eine Reducer- Struktur vor, mit der Sie einem Array Zahlen hinzufügen können:

@dynamicCallable struct Reducer { ... } 

Dann müssen Sie eine oder beide der folgenden Methoden implementieren:

 func dynamicallyCall(withArguments: ExpressibleByArrayLiteral) func dynamicallyCall(withKeywordArguments: ExpressibleByDictionaryLiteral) 

Mit der ersten Funktion können Sie auf das Objekt zugreifen, indem Sie ein Array als Argumente übergeben. Mit der zweiten Funktion können Sie auf das Objekt zugreifen, indem Sie dasselbe Array wie die Argumente übergeben, jedoch die Namen der Argumente verwenden.

Eine Implementierung der ersten Funktion für eine Reducer- Struktur würde beispielsweise folgendermaßen aussehen:

 func dynamicallyCall(withArguments arguments: [Int]) -> Int { return arguments.reduce(0, +) } 

Wenden Sie dann eine solche Struktur wie folgt an:

 let reducer = Reducer() let sum = reducer(1, 2, 3) // sum = 6 

Wir werden die Implementierung der zweiten Methode am Beispiel der Komparatorstruktur betrachten , mit der wir zwei Zahlen vergleichen können:

 @dynamicCallable struct Comparator { func dynamicallyCall(withKeywordArguments arguments: KeValuePairs<String, Int>) -> ComparisonResult { guard let lhs = arguments["lhs"], let rhs = arguments["rhs"], lhs != rhs else { return .orderedSame } return lhs > rhs ? .orderedDescending : .orderedAscending } } 

Sie können diese Struktur wie folgt verwenden:

 let comparator = Comparator() let comparisionResult = comparator(lhs: 1, rhs: 2) // comparisionResult = .orderedAscending 

Unbekanntes Attribut im Schalter ( SE-0192 )


Viele Menschen wissen, dass es bei der Verarbeitung von Aufzählungswerten erforderlich ist, alle Fälle zu beschreiben und nicht die Standardeinstellung zu verwenden. Diese Anforderung erhöht zwar die Sicherheit, hat jedoch auch einen Nachteil, da Sie beim Ändern von Werten in der Aufzählung deren Verarbeitung hinzufügen müssen. Es besteht immer noch die Möglichkeit, dass das Systemframework eine der Aufzählungen ändert, dies wurde jedoch in Ihrer Anwendung nicht verarbeitet (z. B. mit LABiometryType ).

Swift 5 fügt das unbekannte Attribut hinzu, mit dem Sie bei der Verarbeitung einer Aufzählung zwei verschiedene Szenarien trennen können:

  • Der Standardcode sollte für alle Fälle ausgeführt werden, die nicht im Switch verarbeitet wurden
  • Alle Fälle werden in switch verarbeitet. Wenn neue hinzugefügt werden, müssen Sie standardmäßig den Code verwenden

Schauen wir uns ein Beispiel an:

 enum HTTPMethod { case post, get, put } //  @unknown switch httpMethod { case .post: print("Post") case .get: print("Get") default: print("Put") } //  @unknown switch httpMethod { case .post: print("Post") case .get: print("Get") @unknown default: print("Unknown HTTP method") } 

Double Optional als Ergebnis des Aufrufs einer Funktion mit try loswerden? ( SE-0230 )


Sicherlich sind viele auf die Tatsache gestoßen, dass beim Aufrufen der Throwable-Funktion, die Optional zurückgibt, try? Das Ergebnis ist ein Typ, der in zwei optionale Optionen eingeschlossen ist . Dies ist nicht sehr praktisch, und rufen Sie in Swift 5 try an? In diesem Fall wird ein Typ zurückgegeben, der nur in eine Option eingeschlossen ist .

So war es vor Swift 5:

 let result = try? optionalObject?.foo() // type(of: result) = SomeType?? 

Und so wird es in Swift 5 sein:

 let result = try? optionalObject?.foo() // type(of: result) = SomeType? 

Multiplizitätsprüfung ( SE-0225 )


Um die Vielzahl einer Zahl zu einer anderen zu überprüfen, können Sie anstelle des Restes der Division (%) die Funktion isMultiple (of :) verwenden :

 //   let isEven = 4 % 2 == 0 //   let isEvent = 4.isMultiple(of: 2) 

Die Änderung ist geringfügig, macht den Code jedoch etwas klarer und vereinfacht die Suche nach Code.

Zählen der Anzahl der Elemente in einer Sequenz mit einer Bedingung ( SE-0220 )


In Swift 5 fügt der Sequenztyp die Methode count (wobei: (Element) -> Bool) -> Int hinzu , mit der Sie die Anzahl der Elemente in einer Sequenz zählen können, die eine bestimmte Bedingung in einem Durchgang erfüllen. Vorher musste ich Filter in Verbindung mit count verwenden . Diese Methode speichert den zugewiesenen Speicher, wenn ein neues Array in der Filtermethode erstellt wird.

Ein Beispiel:

 let countOfZeroes = [0, 1, 2, 0, 4].count(where: { $0 == 0 }) // countOfZeroes = 2 

CompactMapValues-Methode im Wörterbuch ( SE-0218 )


Diese Methode kombiniert compactMap aus Array und mapValues aus Dictionary . Durch Aufrufen dieser Methode wird ein Wörterbuch mit transformierten Werten erstellt, in dem keine Werte gleich Null vorhanden sind .

Ein Beispiel:

 let dictionary = ["a": "1", "b": "2", "c": "Number"] let resultDictionary = dictionary.compactMapValues { Int($0) } // resultDictionary = ["a": 1, "b": 2] 

Rohe Saiten ( SE-0200 )


Es wurde die Möglichkeit hinzugefügt, Zeilen zu schreiben, in denen Anführungszeichen und Backslashes als reguläre Zeichen und nicht als Sonderzeichen verwendet werden. Fügen Sie dazu das Zeichen # am Anfang und am Ende der Zeile hinzu.

Ein Beispiel:

 let string1 = #"   " ""# let string2 = #"  \ "# 

Wenn Sie beim Erstellen einer Zeile eine Variable einfügen, müssen Sie nach dem Backslash das # -Zeichen hinzufügen:

 let string = #"   \#(variable)"# 

Wenn die Zeile ein # -Zeichen hat, müssen Sie am Anfang und am Ende der Zeile zwei ## -Zeichen hinzufügen:

 let string = ##"   #"## 

Das Sequenzprotokoll enthält keine zugeordnete SubSequence vom Typ ( SE-0234 )


Der assoziative Typ von SubSequence wurde aus dem Sequenzprotokoll in Collection verschoben . Jetzt geben alle Methoden in Sequence , die SubSequence zurückgegeben haben, einen bestimmten Typ zurück. Beispielsweise gibt die Suffix- Methode jetzt ein Array zurück . Hier ist die vollständige Liste der von dieser Änderung betroffenen Methoden:

 extension Sequence { public func dropFirst(_ k: Int = 1) -> DropFirstSequence<Self> public func dropLast(_ k: Int = 1) -> [Element] public func suffix(_ maxLength: Int) -> [Element] public func prefix(_ maxLength: Int) -> PrefixSequence<Self> public func drop(while predicate: (Element) throws -> Bool) rethrows -> DropWhileSequence<Self> public func prefix(while predicate: (Element) throws -> Bool) rethrows -> [Element] public func split( maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true, whereSeparator isSeparator: (Element) throws -> Bool ) rethrows -> [ArraySlice<Element>] } 

Jetzt wird die Arbeit mit diesen Methoden einfacher.

Protokollbeschränkungen


Protokolle unterstützen jetzt die Einschränkung in Form von Klassen, die dieses Protokoll implementieren. Mit anderen Worten, Sie können jetzt angeben, dass ein Protokoll nur von einer bestimmten Klasse implementiert werden kann. Zum Beispiel:

 protocol Viewable: UIView {} protocol Viewable where Self: UIView {} 

Die zweite Aufnahmeoption wird in Swift 4.2 unterstützt, kann jedoch einen Kompilierungsfehler oder eine Laufzeit verursachen. In Swift 5 tritt dieser Fehler nicht auf.

Fazit


Dies ist keine vollständige Liste der Änderungen in Swift 5, hier werden nur die wichtigsten Änderungen erfasst. Im Allgemeinen sind die vorgestellten Änderungen positiv und machen die Sprache verständlicher und flexibler. Die Hauptsache ist, dass "In aktuelle Swift-Syntax konvertieren" schmerzlos sein sollte.

Das ist alles, danke fürs Lesen.

Source: https://habr.com/ru/post/de437942/


All Articles