Quoi de neuf dans Swift 5?

Salut, je m'appelle Ilya. Je suis développeur iOS sur Tinkoff.ru. Dans cet article, je donnerai un bref aperçu des principales modifications de Swift 5. Ces modifications sont décrites dans les notes de publication . Pour ceux qui ne se sont pas encore familiarisés, bienvenue au chat!



La taille de l'application va diminuer!


Les applications écrites dans Swift 5 et compilées pour iOS 12.2, watchOS 5.2, tvOS 12.2 n'incluront pas de bibliothèques dynamiques pour la bibliothèque standard Swift et le SDK Swift. Et cela signifie que la taille de l'application ne diminuera cependant pas de beaucoup. Si vous croyez ce tweet , la taille du projet vide a été réduite de 2,4 Mo à 24 Ko. Un bon résultat pour les petites applications, mais pour les grandes applications il n'y aura pas beaucoup de différence.

@dynamicCallable ( SE-0216 )


L'attribut @dynamicCallable vous permet de travailler avec un objet en tant que fonction. Ces objets sont appelés objets fonctionnels ou foncteurs (plus de détails peuvent être trouvés ici ). Les objets fonctionnels sont en C ++, Python, JavaScript et dans d'autres langages, et dans Swift ils ont été ajoutés pour des raisons de compatibilité avec ces langages. Le fait est que Swift interagit désormais bien avec l'API C et Objective-C, et les développeurs de langage veulent ajouter une interaction avec les langages dynamiques - Python, JavaScript, Ruby et autres.

Pour faire d'un type un foncteur, vous devez ajouter l'attribut @dynamicCallable à sa déclaration. Prenons un exemple de structure de réducteur qui peut être utilisée pour ajouter des nombres dans un tableau:

@dynamicCallable struct Reducer { ... } 

Ensuite, vous devez implémenter une ou les deux méthodes suivantes:

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

La première fonction vous permet d'accéder à l'objet en passant un tableau comme arguments. La deuxième fonction vous permet d'accéder à l'objet, en passant le même tableau que les arguments, mais en utilisant les noms des arguments.

Par exemple, une implémentation de la première fonction d'une structure Reducer ressemblerait à ceci:

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

Ensuite, appliquez une telle structure comme suit:

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

Nous considérerons l'implémentation de la deuxième méthode en utilisant l'exemple de la structure Comparateur , avec laquelle nous pouvons comparer deux nombres:

 @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 } } 

Vous pouvez utiliser cette structure comme suit:

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

Attribut inconnu dans le commutateur ( SE-0192 )


Beaucoup de gens savent que lors du traitement des valeurs d'énumération, il est nécessaire de décrire tous les cas et d'essayer de ne pas utiliser la valeur par défaut. Bien que cette exigence ajoute une pincée de sécurité, elle présente également un inconvénient, car lorsque vous modifiez des valeurs dans l'énumération, vous devez ajouter leur traitement. Il est toujours possible que la structure du système modifie l'une des énumérations, mais cela n'a pas été traité dans votre application (il en était ainsi, par exemple, avec LABiometryType ).

Swift 5 ajoutera l'attribut inconnu , ce qui vous permettra de séparer 2 scénarios différents lors du traitement d'une énumération:

  • Le code par défaut doit être exécuté pour tous les cas non traités dans le commutateur
  • Tous les cas sont traités dans switch, et si de nouveaux sont ajoutés, vous devez utiliser le code par défaut

Regardons un exemple:

 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") } 

Se débarrasser du double facultatif à la suite de l'appel d'une fonction avec try? ( SE-0230 )


Beaucoup ont sûrement découvert que lors de l'appel de la fonction jetable, qui renvoie Facultatif , en utilisant try? , le résultat est un type encapsulé dans deux Facultatif . Ce n'est pas très pratique, et donc dans Swift 5, appelez essayer? dans ce cas, renvoie un type enveloppé dans un seul Facultatif .

Voici comment c'était avant Swift 5:

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

Et il en sera de même dans Swift 5:

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

Contrôle de multiplicité ( SE-0225 )


Pour vérifier la multiplicité d'un nombre à un autre, vous pouvez utiliser la fonction isMultiple (of :) , au lieu du reste de la division (%):

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

Le changement est mineur, mais il rend le code un peu plus clair et simplifie la recherche par code.

Comptage du nombre d'éléments dans une séquence avec une condition ( SE-0220 )


Dans Swift 5, le type Sequence ajoutera la méthode count (où: (Element) -> Bool) -> Int , qui vous permettra de compter le nombre d'éléments dans une séquence qui satisfont une condition donnée en une seule passe. Avant cela, je devais utiliser le filtre en conjonction avec le comptage . Cette méthode économisera la mémoire allouée lors de la création d'un nouveau tableau dans la méthode de filtrage .

Un exemple:

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

Méthode CompactMapValues ​​dans le dictionnaire ( SE-0218 )


Cette méthode combine compactMap from Array et mapValues from Dictionary . Suite à l'appel de cette méthode, un dictionnaire avec des valeurs transformées est créé dans lequel il n'y a pas de valeurs égales à zéro .

Un exemple:

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

Chaînes brutes ( SE-0200 )


Ajout de la possibilité d'écrire des lignes dans lesquelles les guillemets et les barres obliques inverses sont utilisés comme caractères normaux et non comme caractères spéciaux. Pour ce faire, ajoutez le caractère # au début et à la fin de la ligne.

Un exemple:

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

Si vous insérez une variable lors de la création d'une ligne, après la barre oblique inverse, vous devez ajouter le signe #:

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

Si la ligne a un signe #, au début et à la fin de la ligne, vous devez ajouter deux signes ##:

 let string = ##"   #"## 

Le protocole de séquence ne contient plus de sous-séquence de type associé ( SE-0234 )


Le type associatif SubSequence a été déplacé du protocole Sequence vers Collection. Désormais, toutes les méthodes de Sequence qui ont renvoyé SubSequence renvoient un type spécifique. Par exemple, la méthode du suffixe renvoie désormais un tableau . Voici la liste complète des méthodes affectées par ce changement:

 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>] } 

Maintenant, travailler avec ces méthodes deviendra plus facile.

Restrictions de protocole


Les protocoles prennent désormais en charge la restriction sous la forme de classes qui implémentent ce protocole. En d'autres termes, vous pouvez désormais indiquer qu'un protocole ne peut être implémenté que par une classe spécifique. Par exemple:

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

La deuxième option d'enregistrement est prise en charge dans Swift 4.2, mais peut provoquer une erreur de compilation ou d'exécution. Dans Swift 5, cette erreur ne se produira pas.

Conclusion


Il ne s'agit pas d'une liste complète des modifications dans Swift 5; seules les principales modifications sont collectées ici. En général, les changements présentés sont positifs et rendent le langage plus compréhensible et flexible. L'essentiel est que «Convertir en syntaxe Swift actuelle» devrait être indolore.

C'est tout, merci d'avoir lu.

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


All Articles