info@codabee.com

Apprendre le langage Swift

Les basiques de Swift

Définition

En Informatique, une variable (ou une constante) est un espace alloué dans la mémoire qui permet de stocker une valeur. Les constantes et les variables associent un nom, qui permettra au programme de les stocker et les récupérer à une valeur donnée qui peut être de n’importe quel type (par exemple un nombre 10 ou une chaîne de caractère “Je suis une phrase”).

Différence entre constante et variable

Les constantes et les variables ont la même fonction principale: Stocker une valeur. Elles se différencient sur un point précis: 

  • Les constantes ont une valeur fixe. Elle ne peut pas être modifiée
  • Les variables peuvent être modifiées à tout moment. Le type de valeur doit cependant rester le même. On ne peut pas attribuer une valeur Int (nombre entier) à une variable puis une valeur de type String(chaîne de caractères) plus tard.
Déclarer une constante ou une variable
 
Pour les déclarer nous avons besoin de 4 éléments:
  1. Le mot clé: var pour une variable, let pour une constante.
  2. Le nom de la variable
  3. Le type de valeur (optionnel)
  4. La valeur

Exemple:

 var str: String = “Ma première variable”
Nous pouvons voir ici le mot clé var, le nome de la variable str, qui sera de type String. Nous attribuons ensuite la valeur par le signe “=” puis la valeur que l’on veut.
Si nous voulons traduire en français, cela donnerait: “Déclare une variable que nous appellerons str, qui sera de type String et qui aura une valeur égale à Ma première variable”

let number: Int = 20

Faisons la même chose avec une constante. Cette fois ci nous décidons de lui donner un nom Number avec un type Int et une valeur égale à 20.

 

Le Type Inference

var str = “Ma première variable”

Comme expliqué plus tôt, le type est optionnel.Swift dispose de ce que l’on appelle le type inférence. Il retrouve automatique le type utilisé dans la valeur. Attention toutefois à certaines confusions possibles au niveau des nombres, nous y reviendrons plus tard.

 

Conventions de nommage

Pour avoir une certaine uniformité, il existe des conventions de nommage. Ce sont des bonnes pratiques pour que le code soit lisible et réutilisable par tous. Un nom de variable ou de constante doit être clair et explicite, il commence par une lettre minuscule (ou un “_” pour une variable privée) et utilise le CamelCase. Le CamelCase est utilisé lorsque une variable contient plusieurs mots. Ils sont accolés et chaque première lettre de chaque mot est en majuscule.
exemple: var maPremiereVariable = “Ma première variable”

Modifier les valeurs:

Il est tout à fait possible de modifier la valeur d’une variable mais pas la valeur d’une constante. Pour ceci, il suffit d’appeler le nom de la variable et de lui attribuer une nouvelle valeur. Exemple:

var salutations = “Hello World!”

salutations = “Salut les codeurs!”

 

Essayons maintenant avec un type différent. Comme vous pouvez le voir, une fois que la variable a défini un type, on ne peut plus en changer.

var salutations = “Hello World!”

salutations = 426

Cannot assign a value of type ‘Int’ to type ‘String’

 

Essayons maintenant avec une constante. 

let salutations = “Hello World!”

salutations = “Salut les codeurs!”

Et oui, la constante a une valeur fixe. Nous avons la aussi une erreur de compilation.

 

Le print de base

Le print est une fonction qui permet d’afficher la valeur d’une variable ou constante dans la console. La fonction print s’appelle par son nom de fonction et prend entre parenthèses la variable voulue. On entre donc en paramètre de fonction la valeur que l’on veut connaître.

Exemple:

let nombreDeJoueurs = 11

print(nombreDeJoueurs)

La console affichera 11

Le print et la String interpolation.

A certaines étapes du développement de vos applications, vous aurez besoin de plus de contexte dans vos print, par exemple pour connaître à quel endroit précis ce print est fait, à quel moment, dans quel ordre vos différent points arrivent…. Pour ceci, nous pouvons utiliser la String interpolation.  Plus simplement, cela signifie que l’on va ajouter une ou plusieurs variables à une String. Cette valeur sera à l’intérieur de notre String entourée de  ‘\(‘ et ‘)’

Exemple:  

let nombreDeJoueurs = 11

print(“Nombre de joueurs sur le terrain: \(nombreDeJoueurs)”)

Désormais la console affiche : Nombre de joueurs sur le terrain: 11

Les commentaires sont utilisés pour ajouter du texte non exécutable à votre code. Ils peuvent servir par exemple de note (à quoi sert ce bout de code), ou encore de rappel pour plus tard (ajouter une fonction ici.). Les commentaires sont ignorés par Swift lorsque votre application compile. Ajouter un commentaire est très similaire aux commentaires en C:

Les commentaires sur une seule ligne commencent avec un double ‘/‘.

//Commentaire Simple

 

Les commentaires multilignes commencent par /* et se terminent par */

/*Ligne 1 de Commentaire

 Ligne 2 de Commentaire

Ligne 3 de Commentaire */

 

Vous pouvez aussi commenter à l’intérieur de commentaires. Il vous permettront de décommenter facilement de grands blocs même si ce code contient d’autres commentaires.

/*Commentaire 1

 /* Devinez qui je suis?

Je suis un commentaire à l’intérieur du commentaire 1*/

Fin du commentaire 1*/

 

Contrairement à beaucoup d’autres langages de programmation, l’utilisation du point virgule à la fin de chaque déclaration est optionnel en Swift.

let myConstant = 2

 

let myConstantSemicolon = 3;

 

Ils sont cependant obligatoires si vous avez plusieurs déclarations à faire sur une seule ligne

var value1 = 2; var value2 = 56

 

 

Les nombres entiers sont des nombres qui n’ont pas de virgule comme par exemple 5 ou -34. Les nombres entiers sont signés ou non. La différence est qu’un nombre non signé ne peut pas être négatif. Ils sont sur (8, 16, 32 et 64 bits).

Les nombres signés: Int

Le type de nombre signé est Int, une contraction de Integer, pour nombre entier en anglais. Dans la plupart des cas, il n’est pas utile de spécifier une taille. (Int32 par exemple pour 32 bits). A moins de travailler sur des nombres de taille spécifique, il est conseillé d’utiliser le Int simple pour une question de consistance et d’interopérabilité. 

var myInt = 34

var myInt2: Int = -545

 

Les nombres non signés: UInt.

Le nombre non signé sera UInt. Il ne peut donc pas être négatif. Comme pour les nombres signés, il n’est pas utile de définir une taille spécifique.

Lorsque nous utilisons un nombre entier sans spécifier le type, Swift le met automatiquement en Int et non en Uint

var unsigned: UInt = 2345

var unsignedNegative: UInt = -2

//Nous avons pour le négatif une erreur

 

Tailles selon les bits

Vous pouvez accéder au valeurs minimales et maximales des Int de cette façon:

Les tailles des entiers signés en bits:

  • 8: -128 à 127
  • 16: -32768 à 32767
  • 32: -2147483648 à 2147483647
  • 64: -9223372036854775808 à 9223372036854775807

var myInt32: Int32 = 1545

Les tailles des entiers non signés en bits:

  • 8: 0 à 255
  • 16: 0 à 65535
  • 32: 0 à 4294967295
  • 64: 0 à 18446744073709551615

var myUInt32: UInt32 = 1545

Les nombres décimaux sont des nombres qui ont une virgule Comme par exemple 32,09 ou -14,6 .

 Nous en avons 2: 

Les Double qui sont des décimaux sur 64 bits 

Les Float qui sont des décimaux sur 32 bits

Le type inference caste votre décimal en Double si vous ne spécifiez pas son type.

var decimal = 3.14 //Sera automatiquement un Double

var myFloat: Float = -0.543

var myDouble: Double = 234.835854689

A certains moments du développement de nos applications, nous aurons besoin de convertir des types de nombre. Par exemple de Int vers Float, ou Double vers Int….

Pour ceci, il suffit de spécifier le Type que nous voulons obtenir et mettre la valeur à convertir entre parenthèses.

var decimal = 3.14

var integer:Int = Int(decimal)

Le type String est une chaîne de caractères, comme par exemple “Salut les codeurs”, “Hello world”, “A”, “12”. Tous les caractères mis entre des guillemets. Et oui, le “12” mis entre guillemets n’est pas un Int mais une String. “” Est aussi une String, vide, mais c’est une String.

Nous pouvons la déclarer avec ou sans son type. Swift gèrera automatique son type. et avec ou sans valeur

var string1: String = “Bonjour”

var string2 = “Salut”

var string3String

 

Et si vous voulez faire une String sur plusieurs lignes? Dans ce cas il existe plusieurs façons: ajouter \n pour un saut à la ligne ou le triple “.

var multi1 = “Salut\nComment allez vous?”

 

var multi2 = “””

Bonjour,

 

– Quel temps fait’il aujoud’hui?

– Il fait très beau sur notre belle côte.

– “La vie est belle”

“””

 

print(multi1)

// Salut

// Comment allez vous?

print(multi2)

// Bonjour,

//

// – Quel temps fait’il aujoud’hui?

// – Il fait très beau sur notre belle côte.

// – “La vie est belle”

 

Nous avons même pu ajouter des guillemets dans notre String multi lignes a 3 “.

Initialiser une String sans valeur peut être risqué, une string sans valeur (nil) causera une erreur et donc un crash de votre application. Mieux vaut initialiser une String vide ou avec un constructeur de classe.

var string1 = “”

var string2 = String()

 

La mutabilité des Strings. On peut accoler une valeur à la valeur d’une String avec l’opérateur +=

var mutable = “Je suis une String”

mutable += “, et on peut accoler des valeurs”

print(mutable)

// Je suis une String, et on peut accoler des valeurs

 

Pour modifier une String, nous pouvons utiliser la concaténation: c’est à dire ajouter une string à une autre avec l’opérateur +

var prenom = “Matthieu”

var nom = “Codabee”

var nomComplet = prenom + nom

 

Là nous obtenons MatthieuCodabee. Les 2 Strings ont été accolées et nous n’avons pas dit à Swift d’ajouter un espace. Faisons plutôt ceci:

var nomComplet = prenom + “” + nom

 

L’interpolation de String. Pour intégrer une valeur String ou non dans une String que l’on insère grâce à \(). La valeur à intégrer sera entre les parenthèses.

var age = 25

var name = “Bill”

 

var interpolation = “Salut je m’appelle \(name) et j’ai \(age) ans.”

 

print(interpolation)

//Salut je m’appelle Bill et j’ai 25 ans.

 

Nous pouvons accéder aux caractères d’une String.

Passons à travers chaque caractère grâce à une boucle, les boucles seront vues un peu plus tard en détail.

var nomDeMonChat = “Athena”

 

for character in nomDeMonChat {

    print(character)

}

//A

//t

//h

//e

//n

//a

 

Nous pouvons aussi compter le nombre de caractères dans une String en ajoutant .count apres le nom de la variable..

print(nomDeMonChat.count)

//6

 

Il existe de nombreuses méthodes de la String que nous pouvons utiliser. par exemple.

Mettre en majuscule avec uppercase().

var car = “chevrolet”

print(car.uppercased())

//CHEVROLET

 

Mettre en Minuscule, avec lowercased()

var dontScream = “C’EST PAS BIEN DE TOUT ECRIRE EN MAJUSCULE”

print(dontScream.lowercased())

// c’est pas bien de tout ecrire en majuscule

 

Mettre une majuscule à chaque début de mot,  avec capitalized

var drink = “café sans sucre avec une pointe de lait.”

print(drink.capitalized)

// Café Sans Sucre Avec Une Pointe De Lait.

 

Changer des caractères avec replacent occurrences(of: séquence à remplace, with: séquence qui va remplacer).

var sansE = “Je veux lire une phrase sans voir de e, et je vais mettre des a à la place.”

print(sansE.replacingOccurrences(of: “e”, with: “a”))

//Ja vaux lira una phrasa sans voir da a, at ja vais mattra das a à la placa.

Le Type Booléen (Bool) est un type de valeur appelée valeur logique, car elle est soit vraie (true)  soit fausse (false).

let isCodingCool = true

var sunny = false

Avec l’utilisation d’opérateurs de comparaison, nous pouvons ainsi utiliser un booléen:

var sunny = false

 

if sunny {

    print(“Allons à la plage”)

} else {

    print(“Restons coder à l’intérieur”)

}

Cela fonctionne aussi avec un opérateur ternaire:

print(sunny ? “Allons à la plage”: “Restons coder à l’intérieur”)

 

Dans ces 2 cas, notre console affichera un print “Restons coder à l’intérieur.

 

Mais ce n’est pas tout, un booléen peut aussi être une vérification de valeurs

var value1 = 1

var value2 = 1

print((value1 == value2) ? “Good job”: “Try again”)

Comme les 2 valeurs ici sont identiques , nous aurons dans notre console “Good job”

Le Tuple est un groupe de multiples valeurs réunies dans une valeur unique. Les valeurs à l’intérieur du Tuple peuvent être de n’importe quel type et ne sont pas nécessairement les mêmes. Ces valeurs sont définies entre parenthèses et séparées par une virgule.

Vous avez peut être déjà vu des erreurs http du genre 404 page not found. Ce message est issu d’un Tuple qui regroupe un code d’état de la page ainsi qu’un message. Créons un tuple pour ceci:

let httpsStatus: (Int, String) = (404, “Page not found”)

 

Nous avoir plus de valeurs que ceci. Par exemple, créons une couleur avec rgb et alpha

let color = (0.4, 0.2, 0.75, 1)

//Nous avons ici 4 valeurs, le rouge, le vert, le bleu et l’alpha.

 

Nous pouvons aussi assigner des noms à chacun des éléments du tuple

let httpsStatus: (code: Int, error: String) = (404, “Page not found”)

print(httpsStatus.code)

//404

print(httpsStatus.error)

//Page not found

 

let color = (red: 0.4, green: 0.2, blue: 0.75, alpha: 1)

print(color.red)

//0.4

print(color.green)

//0.2

print(color.blue)

//0.75

print(color.alpha)

//1

 

A partir de ces tuples, nous pouvons les décomposer et obtenir des valeurs pour chaque élément.

let rect = (300, 200)

let (width, height) = rect

print(width)

//300

print(height)

//200

 

 

Et même en obtenir une seule. Pour ceci, les valeurs non désirées seront remplacées par un ‘_’

 

let (widthOnly, _) = rect

print(widthOnly)

//300

 

Un Array permet de stocker de façon ordonnée des valeurs de même type dans une liste. Sa structure se compose d’une suite de valeurs entre crochets séparées chacunes par une virgule.

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

var intArrat: [Int] = [23, 12, 81, 84, 13]

 
Nous pouvons aussi initialiser un array vide de ces 2 façons:
 

var array1 = [Bool]()

var array2: [Double] = [] 

 
Le but d’avoir une liste de valeurs est bien évidemment de stocker ces valeurs à un endroit précis, mais aussi de pouvoir y accéder, que ce soit de manière globale ou individuelle.

 

Prenons myFirstArray: var myFirstArray = [“Pierre”“Paul”“Jacques”]

Si nous voulons voir tous les éléments de notre array, un print suffit. 

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

print(myFirstArray)

//[“Pierre”, “Paul”, “Jacques”]

Nous pouvons aussi compter le nombre d’éléments dans notre array, avec le .count

print(myFirstArray.count)

//3

Nous pouvons voir si notre array est vide avec le .isEmpty

print(myFirstArray.isEmpty)//false

Nous pouvons aussi itérer, c’est à dire passer à travers tous les éléments de notre array avec une boucle. Pour en savoir plus sur les boucles, rendez-vous à la section dédiée:

for element in myFirstArray {

    print(element)

}

//Pierre

//Paul

//Jacques

 

Index:

Comme dit au début, l’array est une liste ordonnée, chaque élément est défini par un index. Le premier élément part de 0, et pas de 1. Ceci est très important, donc je le répète, l’index commence à 0. Si je veux accéder au premier élément, j’écris entre crochets l’index de l’élément que je veux récupérer.

let first = myFirstArray[0]

print(first)

//Pierre 

let second = myFirstArray[1]

print(second)

//Paul

 

Je peux aussi accéder au premier élément grâce au Count que nous avons. Cependant, il faut faire attention car le count compte le nombre d’éléments et notre index par de 0, pour ne pas avoir d’erreur, le dernier élément sera Count – 1:

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

let last = myFirstArray[myFirstArray.count 1]

print(last)

//Jacques 

Nous pouvons aussi accéder au premier et dernier élément d’un array avec .first et .last. Attention, lors de la récupération de cette valeur, Swift n’est pas sûr d’obtenir une valeur, il n’est pas sûr qu’il y ait des éléments dans notre array, le résultat sera donc un optionnel. Pour en savoir plus sur les optionnels, une section y est dédiée.

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

let last = myFirstArray.last

let first  = myFirstArray.first

print(last)

//Optional(“Jacques”)

print(first)

//Optional(“Pierre”)

 

Ajout

Nous pouvons ajouter des éléments à notre array. Sous réserve que celui-ci soit une variable et non une constante bien évidemment. Pour ceci, nous pouvons utiliser la méthode append qui s’utilise de 2 façons, newElement, ou contentOf.

newElement nous permet d’ajouter un élément. Qui sera ajouté en fin d’array:

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

//myFirstArray.append(newElement: String)

myFirstArray.append(“Sylvain”)

print(myFirstArray)

//[“Pierre”, “Paul”, “Jacques”, “Sylvain”]

 

contentOf nous permet d’ajouter une séquence, c’est à dire un array à un autre array:

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

//myFirstArray.append(contentsOf: Sequence)

myFirstArray.append(contentsOf: [“Marie”, “Julie”, “Audrey”])

print(myFirstArray)

//[“Pierre”, “Paul”, “Jacques”, “Marie”, “Julie”, “Audrey”]

 

On peut aussi ajouter un array à un array avec l’opérateur +=

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

myFirstArray += [“Leo”, “Chris”]

print(myFirstArray)

//[“Pierre”, “Paul”, “Jacques”, “Leo”, “Chris”]

 

Insertion

Nous pouvons aussi insérer un ou plusieurs éléments à un array à un endroit précis grâce à l’index, pour ceci la méthode append sera remplacée par insert. Nous avons aussi le newElement pour un élément unique et contentOf pour un array à insérer.

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

//myFirstArray.insert(newElement: String, at: Int)

myFirstArray.insert(“Bob”, at: 1)

print(myFirstArray)

//[“Pierre”, “Bob”, “Paul”, “Jacques”]

Ou bien

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

//myFirstArray.insert(contentsOf: Collection, at: Int)

myFirstArray.insert(contentsOf: [“Riri”, “Fifi”, “Loulou”], at: 2)

print(myFirstArray)

//[“Pierre”, “Paul”, “Riri”, “Fifi”, “Loulou”, “Jacques”]

 

Suppression

Les méthodes Remove permettent de supprimer un élément d’un Array.

Le remove at index: Selon un index choisi

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

myFirstArray.remove(at: 1)

print(myFirstArray)

//[“Pierre”, “Jacques”]

 

Le removeFirst() pour le premier élément:

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

myFirstArray.removeFirst()

print(myFirstArray)

//[“Paul”, “Jacques”]

 

Le removeLast pour le dernier élément:

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

myFirstArray.removeLast()

print(myFirstArray)

//[“Pierre”, “Paul”]

Vider un Array

Pour vider un array, nous pouvons lui attribuer une nouvelle valeur vide ‘[]’ ou utiliser la méthode removeAll()

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

myFirstArray = []

print(myFirstArray)

//[]

 

ou

var myFirstArray = [“Pierre”, “Paul”, “Jacques”]

myFirstArray.removeAll()

print(myFirstArray)

//[]

Les Dictionnaires sont des listes qui vont un peut ressembler aux Array mais qui vont avoir plusieurs différences:

  • Les Dictionnaires ne sont pas ordonnés. Les valeurs peuvent donc apparaître dans le désordre
  • Ils ne sont pas accessible par un index mais par une ‘key’
  • Ils stockent donc une liste d’éléments contenant une clé (key) et une valeur(value)
Ils ont des points communs:
  • Ils stockent une liste d’éléments
  • Ils doivent avoir le même type
  • La liste des éléments est entre crochets
  • Certaines méthodes sont semblables(isEmpty par exemple)

Sa structure se compose d’une suite entre crochets  de clés et valeurs, séparées par ‘:’ elles mêmes séparées par une virgule.

var dict = [“Key1”: 1, “Key2”: 2, “Key3”: 3]

print(dict)

//[“Key1”: 1, “Key2”: 2, “Key3”: 3] . Les Clés sont des String, les valeurs des Int. vous pouvez utiliser n’importe quel type

 
 

Nous pouvons aussi initialiser un Dictionnaire vide de ces 3 façons:

var dict = [String: Bool]()

 

var dict2 : [Int: String] = [:]

 

var dict3 = Dictionary<String, Int>()

 
 
  

Nous pouvons aussi compter le nombre d’éléments dans notre Dict, avec le .count

var dict = [“Jean”: 30, “Julie”: 19, “Sophie”: 27, “Samy”: 42, “Sandra”: 54, “Joy”: 14, “Max”: 34]

print(dict.count)

//7

 

Nous pouvons voir si notre dictionnaire est vide avec le .isEmpty

var dict = [“Jean”: 30, “Julie”: 19, “Sophie”: 27, “Samy”: 42, “Sandra”: 54, “Joy”: 14, “Max”: 34]

print(dict.isEmpty)

//false

 

Nous pouvons aussi itérer, c’est à dire passer à travers tous les éléments de notre dictionnaire avec une boucle. Pour en savoir plus sur les boucles, rendez-vous à la section dédiée:

var dict = [“Jean”: 30, “Julie”: 19, “Sophie”: 27, “Samy”: 42, “Sandra”: 54, “Joy”: 14, “Max”: 34]

for (key, value) in dict {

    print(“Je suis \(key) et j’ai \(value) ans.”)

}

/*

 Je suis Samy et j’ai 42 ans.

 Je suis Sophie et j’ai 27 ans.

 Je suis Max et j’ai 34 ans.

 Je suis Julie et j’ai 19 ans.

 Je suis Joy et j’ai 14 ans.

 Je suis Jean et j’ai 30 ans.

 Je suis Sandra et j’ai 54 ans.

*/

 

Vous pouvez voir que le dictionnaire n’est pas ordonné, nous n’avons pas récupéré les éléments dans le même ordre et que nous devons dans notre boucle récupérer un tuple qui sera notre key et notre value.

 

Accéder à un élément: 

Cela fonctionne  à peu près comme pour les éléments d’un Array:

var dict = [“Jean”: 30, “Julie”: 19, “Sophie”: 27, “Samy”: 42, “Sandra”: 54, “Joy”: 14, “Max”: 34]

print(dict.first)

print(dict[“Jean”])

print(dict[“Bob”])

/*

 Optional((key: “Samy”, value: 42))

 Optional(30)

 nil

*/

 

  •  vous avez le first: qui est optionnel et renvoie à la fois la clé et la valeur. Etant donné que le dictionnaire n’est pas ordonné, vous aurez un élément au hasard.
  • Vous n’avez pas le last
  • Vous pouvez aller chercher via la key. Vous aurez en résultat la valeur correspondant à la key en optionnel. Cette key peut exister ou pas.

Modifier et ajouter:

var dict = [“Jean”: 30, “Julie”: 19, “Sophie”: 27, “Samy”: 42, “Sandra”: 54, “Joy”: 14, “Max”: 34]

dict[“Jean”] = 79

print(dict)

//[“Max”: 34, “Sophie”: 27, “Samy”: 42, “Joy”: 14, “Jean”: 79, “Sandra”: 54, “Julie”: 19]

dict[“Simon”] = 2

print(dict)

//[“Max”: 34, “Sophie”: 27, “Samy”: 42, “Joy”: 14, “Jean”: 79, “Sandra”: 54, “Julie”: 19, “Simon”: 2]

Pour modifier une valeur d’un dict, il suffit de récupérer un élément via sa clé et lui attribuer une valeur. Si la clé n’existe pas, un nouvel élément sera créé.

 

Il existe aussi le updateValue qui aura la même utilité:

var dict = [“Jean”: 30, “Julie”: 19, “Sophie”: 27, “Samy”: 42, “Sandra”: 54, “Joy”: 14, “Max”: 34]

dict.updateValue(35, forKey: “Sophie”)

print(dict)

//[“Max”: 34, “Sandra”: 54, “Sophie”: 35, “Samy”: 42, “Joy”: 14, “Jean”: 30, “Julie”: 19]

 

Suppression

Le removeValue: Selon une clé choisie:

var dict = [“Jean”: 30, “Julie”: 19, “Sophie”: 27, “Samy”: 42, “Sandra”: 54, “Joy”: 14, “Max”: 34]

dict.removeValue(forKey: “Jean”)

print(dict)

//[“Max”: 34, “Joy”: 14, “Sandra”: 54, “Samy”: 42, “Julie”: 19, “Sophie”: 27]

 

le removeAll() pour tout supprimer:

var dict = [“Jean”: 30, “Julie”: 19, “Sophie”: 27, “Samy”: 42, “Sandra”: 54, “Joy”: 14, “Max”: 34]

dict.removeAll()

print(dict)

//[:]

 

Swift est un langage sensible, si une variable ou une valeur est nil, l’application va cracher et s’arrêter et c’est quelque chose que nous voulons absolument éviter.

Pour ceci, il existe les optionnels. L’optionnel n’est pas un type en lui même mais une façon sûre de dire que telle ou telle variable a le droit de ne pas avoir de valeur (être nil). Pour utiliser un optionnel, nous allons ajouter un ? après le choix du type de variable ou constante

var nonOptional: String

var optional: String?

 

print(nonOptional)

 

Si nous essayons de faire un print de nonOptional, nous avons une erreur. Par contre, si nous faisons un print de optional:

print(optional)

//nil

 

Nous avons obtenu nil (pas de valeur) dans la console. Ajoutons des valeurs maintenant.

nonOptional = “Je suis non optionnelle”

optional = “Je suis optionnelle”

print(nonOptional)

//Je suis non optionnelle

print(optional)

//Optional(“Je suis optionnelle”)

 

nonOptional n’a plus d’erreur car elle a désormais une valeur. Par contre le print de optional décrit bien la valeur comme optionnelle.

Lorsque nous devrons utiliser une valeur optionnelle, nous devrons ‘déballer’ cette valeur pour la rendre non optionnelle avec un ! à la fin du nom de la variable. 

print(optional!)

//”Je suis optionnelle”

 

Et voila, nous avons a nouveau une valeur non optionnelle, mais à nouveau sensible au crash si la valeur est nil.

Nous verrons dans les conditions comment gérer ceci.

Les opérateurs

Un opérateur est un symbole spécial qui permet de vérifier, modifier ou combiner des valeurs. Nous avons déjà utilisé un opérateur: le symbole ‘=‘ pour attribuer ou modifier la valeur d’une variable.

Les opérateurs peuvent être classés en plusieurs catégories. Chaque catégorie sera vue en détail dans les sections suivantes:

  • L’opérateur d’assignation.
  • Les opérateurs arithmétiques.
  • Les opérateurs combinés.
  • Les opérateurs de comparaison.

Les opérateurs peuvent être unaires (unary), binaires (binary) ou ternaires (ternary):

  • Les Opérateurs unaires opérent sur une cible unique. Ce sont soit des unaires préfixes si l’opérateur est placé immédiatement avant la valeur (-valeur) ou des unaires suffixes si l’opérateur est placé immédiatement après la valeur(valeur!).
  • Les opérateurs binaires opèrent sur 2 cibles. L’opérateur est donc placé entre les 2 cibles (valeur1 + valeur2)
  • Les opérateurs ternaires opèrent eux sur 3 cibles. Swift ne dispose que d’un opérateur ternaire qui est un opérateur conditionnel (valeur1 ? valeur2 : valeur3).

L’opérateur d’assignation est l’opérateur ‘=’. Il sert à assigner ou modifier la valeur d’une variable:

 

var maVariable = 3

//maVariable est égale à 3

maVariable = 5

//maVariable est désormais égale à 5

Les opérateurs arithmétiques sont les opérateurs qui permettent de faire des calculs. Nous avons les opérateurs classiques:

  • Addition : +
  • Soustraction: –
  • Multiplication: *
  • Division: /

let number1 = 13

let number2 = 5

 

let addition = number1 + number2

print(addition)

//18

let soustraction = number1 number2

print(soustraction)

//8

let multiplication = number1 * number2

print(multiplication)

//65

let division = number1 / number2

print(division)

//2

Les opérations se font sur des variables ou constantes de même type. Si nous essayons avec un Int et un Double, vous obtiendrez une erreur:

let number1: Int = 13

let number2: Double = 5

 

let addition = number1 + number2

//Binary operator ‘+’ cannot be applied to operands of type ‘Int’ and ‘Double’

 

Et avec 2 décimaux de type différent?

let number1: Float = 13

let number2: Double = 5

 

let addition = number1 + number2

 

//Binary operator ‘+’ cannot be applied to operands of type ‘Float’ and ‘Double’

 

Nous devons donc convertir un des 2 nombres pour avoir une opération de possible:

let number1: Float = 13

let number2: Double = 5

 

let addition = number1 + Float(number2)

print(addition)

//18.0

 

Revenons sur notre division entre les 2 Int:

let division = number1 / number2

print(division)

//2

 

Nous obtenons 2. Alors que 13 / 5 n’est pas exactement égal à 2, mais 2,…Pourquoi alors? Car une division entre 2 Int donne un Int. Il n’y a pas d’arrondi mais de division faite complètement. Je m’explique de façon plus imagée. Nous avons 13 oeufs. Combien de boites de 5 pouvons nous remplir? La réponse est 2. Il nous restera 3 oeufs qui ne pourront pas remplir une boite entière.

Et c’est la qu’intervient un dernier opérateur arithmétique: le modulo ou remainder (%). Il nous donne en résultat ce qu’il reste aprèss une division. Si nous reprenons l’exemple des oeufs, nous avons 3 oeufs qui restent.

let number1 = 13

let number2 = 5

 

let modulo = number1 % number2

print(modulo)

//3

 

Passons aux unaires maintenant. En mettant – directement une valeur, nous pouvons changer sa valeur de positif à négatif:

let negative = -3.27

let positive = 43

 

print(negative)

//3.27

print(-positive)

//-43

 

L’opérateur composé. il permet d’assigner d’ajouter ou soustraire une valeur à une variable en combinant un opérateur arithmétique et un opérateur d’assignation:

var un = 34.6

un += 5.4

print(un)

//40.0

un -= 10

print(un)

//30.0

 

C’est comme si nous avions écrit ceci:

un = un + 5.4

un = un 10

 

Nous disposons aussi d’opérateurs pour comparer. Nous avons:

  • Egal à (a == b)
  • Différent de (a != b)
  • Plus grand que (a > b)
  • Plus petit que (a < b)
  • Plus grand ou égal à (a >= b)
  • Plus petit ou égal à (a <= b)
Cette comparaison nous renvoie un booléen:

var a = 5

var b = 7

 

print(a == b)

// false: 5 n’est pas égal à 7

print(a != b)

// true: 5 est différent de 7

print(a > b)

// false: 5 est plus petit que 7

print(a < b)

// true: 5 est plus petit que 7

print(a >= b)

//false: 5 n’est pas égal ou plus grand que 7

print(a <= b)

//true: 5 n’est pas égal mais est plus petit que 7 

 
 

&& et qui signifie ‘et’ et || qui signifie ‘ou’, sont des opérateurs pour combiner plusieurs conditions ou comparaisons:

var a = 6

var b = 9

 

//Verifions si a est égal à b et que a est pair

// Nous voyons que a est pair mais pas égal a b

print((a == b) && (a % 2 == 0))

//false

//maintenant si nous essayons avec ou

print((a == b) || (a % 2 == 0))

//true: une des 2 conditions est remplie

 

Avec un opérateur ternaire, nous pouvons utiliser un opérateur de comparaison et obtenir une valeur selon si cela nous retourne true ou false. Si la comparaison nous retourne true, la valeur assignée sera celle apres le ‘?’, si cela nous retourne false, la valeur assignée sera après le ‘:’

let string = (a == b) ? “Nous sommes pareils”: “Nous sommes différents”

print(string)

//Nous sommes différents

 

Les Boucles

Au fur et à mesure du développement de nos applications, il est indispensable d’avoir un moyen de pour passer à travers toutes les valeurs d’un array, d’un dictionnaire, d’une échelle de valeurs et bien d’autres choses. Pour cela, il existe ce que l’on appelle les boucles.
Prenons par exemple un array de prénom, il serait pratique de pouvoir énumérer un par un ses prénoms.
Il existe plusieurs sortes de boucles, qui chacune vont nous servir à différents moments et pour diverses raisons.

La For in Loop est une boucle qui passe à travers tous les éléments d’une séquence comme par exemple un Array ou un Dictionnaire, mais aussi une échelle de nombres, ou les caractères dans une String. C’est la plus simple à utiliser.
Pour l’utiliser dans un Array:

let listeDeCourses = [“Salade”, “Tomates”, “oignons”, “courgettes”, “tofu”, “quinoa”, “avocat”, “fromage 0%”]

 

for article in listeDeCourses {

    print(“article à acheter: ” + article)

}

 

Nous pouvons voir la structure de la for in loop. Le mot clé for permet de donner une constante temporaire à chaque élément de l’array qui aura pour nom le nom donné après le for (ici article). Ensuite nous avons le mot clé in qui nous dit à travers quelle séquence nous devons passer en revue tous les éléments (ici notre array listeDeCourses). Ensuite, entre les accolades, nous définissons le code à effectuer sur chaque constante créée, chaque article de notre liste de cours dans notre cas.

Faisons la même chose pour un dictionnaire:

let dictForVegan = [“blanc de poulet”: false, “Tomates”: true, “oignons”: true, “quiche lorraine”: false, “tofu”: true, “quinoa”: true, “glace à l’italienne”: false, “gateau au chocolat”: false]

 

for (key, value) in dictForVegan {

    let reponse = value ? “est” : “n’est pas”

    print(key + ” “ + reponse + ” un plat végan”)

}

 

Le Dictionnaire comprend une clé et une valeur, notre boucle retourne donc un tuple au lieu de retourner une simple constante. Nous avons nommé dans notre tuple les valeur key et value mais nous aurions pu les nommer comme nous voulons. Comme pour le for in avec un array, nous créons des valeurs temporaires associées à ces noms.

Avez vous remarqué que lors du run de la playground avec code les array étaient dans l’ordre mais pas les dictionnaires? Les éléments d’un array ont un index et les éléments d’un dictionnaire sont naturellement désordonnés et se récupèrent individuellement par leur clé (key).

Pour passer à travers toutes les lettres d’une String (tous les caractères plus précisément, les espaces, ponctuation et autres sont compris), il suffit de procéder comme pour un array. Si on y réfléchit bien , une phrase est une liste de caractères !

let phrase = “Salut les codeurs!”

for lettre in phrase {

    print(lettre)

}

La for in avec gamme (range en anglais) est une boucle qui va passer à travers des éléments selon un index précis de début et de fin. Voyons cela en action

for index in 110 {

    print(“Index => \(index)”)

}

 

Nous avons toujours notre for suivi d’un nom de constante temporaire créé, puis notre in. Voyons ensuite. La nous avons une gamme, avec in Int de début suivi de … et d’un Int de fin. Cela signifie que le 1 sera la valeur attribuée de départ à l’index, à chaque fois que nous passerons à travers cette boucle, l’index aura +1 (auto incrémentation) jusqu’a ce que cet index arrive à 10. Une fois arrivé a 10, la boucle s’arrête.

Et si nous ne voulons pas aller jusqu’au bout? Nous avons au lieu de …, le ..<. Tant que nous sommes inférieurs à la valeur de fin. 

for index in 1..<10 {

    print(“Index => \(index)”)

}

 

A quoi cela nous servirait? Pour un array par exemple.

let newArray = [“Chat”, “Chien”, “Cheval”, “Cochon”]

for x in 0..<newArray.count {

    print(“Animal commencant par la lettre C: ” + newArray[x])

} 

 

En effet, l’index d’un array commence à  0. Donc le dernier élément sera égal à newArray.count – 1. D’ou l’intérêt de ne pas aller au bout et ne pas avoir d’erreur.

 

Imaginons que nous ne voulons pas toutes les valeurs dans une boucle, mais que les valeurs qui ont chiffre pair:

let recurrence = 2

let start = 0

let end = 50

for pair in stride(from: start, to: end, by: recurrence) {

    print(pair)

}

 

Le from définit la valeur de départ de l’index, le cola valeur de fin.Avec le to nous n’allons pas jusqu’ a 50 C’est comme, si nous avions un 0..<50

Par contre avec le through, nous allons jusqu’a 50, comme le 0…50

for pair in stride(from: start, through: end, by: 5) {

    print(pair)

}

 

Pour itérer à travers chacun des éléments d’un Array, il existe aussi  forEach. Ce n’est pas à proprement parlé une boucle mais plutôt une méthode avec closure. Nous verrons les clôtures dans le chapitre sur les fonctions.

Ce qu’il faut savoir à ce point de notre apprentissage: La méthode forEach permet de prendre chacun des éléments séparément et attribue la valeur et crée une constante constante (entre parenthèses).

Nous pouvons ainsi entre les accolades effectuer le code et interagir avec la constante de chaque élément de l’array. 

var animaux = [“Chat”, “Chien”, “Renard”, “Vache”, “Poule”]

 

animaux.forEach { (animal) in

    print(animal)

}

 

/*

 Chat

 Chien

 Renard

 Vache

 Poule

*/

 

La différence entre une boucle for et une boucle while est que la boucle while continue jusqu’a ce qu’une condition devienne fausse. On utilise cette boucle quand nous ne savons pas à quelle moment nous allons trouver ce que nous cherchons, et donc combien de fois nous allons devoir itérer, passer dans la boucle.

var moutons = 20

 

while moutons > 0 {

    moutons -= 1

    print(“Insommnie: il me reste à compter \(moutons) moutons avant de dormir”)

}

 

Elle se définit par le mot clé while qui vérifie une condition. Si la condition est remplie, le code est exécuté.

Essayons avec un compte négatif au départ (var mouton = -3 par exemple) , nous n’entrons jamais dans la boucle.

 

La repeat while, se compose légèrement différemment de la boucle While. Nous avons un nouveau mot clé repeat. Le code entre accolades et le while à la fin qui vérifie si la condition est toujours bonne pour continuer.

var recidive = 0

 

repeat {

    recidive += Int.random(in: 13)

    print(“Excès de vitesse. Cela fait \(recidive) fois ce mois ci”)

} while recidive < 10

 

print(“Allez hop en prison”)

 

Mais si récidive «est de 6 au début de la boucle? Nous passons une fois dans la boucle.

Voila la différence entre while et repeat while: Le while regarde toujours si la condition est remplie alors que repeat passe une première fois avant de vérifier.

Les Conditions

Au cours du développement de vos applications, vous serez amenés à exécuter certaines portions de code selon certaines conditions.

Par exemple, nous pouvons exécuter du code si l’utilisateur est authentifié, si un joueur est actif, si nous avons bien entré une valeur dans une zone de texte….

Pour ceci, Swift nous propose plusieurs solutions: 

  • La condition if
  • la condition Switch
  • la condition guard

La condition if est la plus simple. If, se traduit en français par si. Donc, si la condition est respectée, le code dans les accolades sera effectué.

Exemples:

var isAuth = false

 

if isAuth {

    print(“Utilisateur est authentifié”)

}

//if isAuth, nous vérifions si isAuth est true. Cela peut s’écrire: if isAuth == true

 

var age = 18

 

if age >= 18 {

    print(“Vous pouvez entrer dans ce lieu réservé aux adultes”)

}

 

Si la condition n’est pas remplie, le code ne sera pas effectué et nous passons au code après les accolades.

Nous pouvons aussi avoir 2 possibilités if else. Si Sinon en français. Si la condition est remplie, nous effectuons le code apres les accolades suivant la condition, sinon, nous effectuons le code après les accolades suivant le sinon

Exemple:

var currentWeight = 59

var targetSize = 60

 

if currentWeight > targetSize {

    print(“File au sport et mange de la salade”)

} else {

    print(“C’est bien, tu peux prendre une glace”)

}

// En jouant avec les valeurs, vous effectuez le code du if ou du else

 

Et si nous avions plusieurs possibilités, plus que 2? Nous avons le if, else if, else. Si, sinon si, sinon

Le code va verifier si la 1ere condition est remplie, sinon il passe au else if… Ainsi de suite jusqu’au else si aucune condition n’est remplie.

var iOSVersion: Int = 14

 

if iOSVersion < 3 {

    print(“Indy, tu as trouvé une relique”)

} else if iOSVersion < 8 {

    print(“Tu prends soin de tes affaires, les iPhones tournant sous cet OS sont anciens”)

} else if iOSVersion < 13 {

    print(“On peut développer avec Swift et UIKit à partir d’iOS 8”)

} else if iOSVersion == 13 {

    print(“Vous pouvez utiliser SwiftUI pour développer des applications”)

}    else {

    print(“Un iPhone du futur”)

} 

Le Switch est une déclaration qui prend une valeur donnée et les compare avec d’autres valeurs proposées. Si la valeur correspond au cas, le code sera exécuté.

le mot clé est Switch, suivi de la valeur à comparer. Entre accolades sont énumérés les propositions. Chaque cas commence par le mot clé case suivie de la valeur, puis ‘:’ et enfin le code à effectuer

Si les cas ne sont pas exhaustifs, c’est à dire si toutes les possibilités ne sont pas énumérées, un default doit être ajouté. Il est l’équivalent du else.

Le default ressemble au case a part que le mot clé sera default.

Exemple :

let language = “French”

 

switch language {

case “French”: print(“Bonjour”)

case “English”: print(“Good morning”)

case “Dutch”: print(“Goedemorgen”)

case “German”: print(“Guten morgen”)

case “Spanish”: print(“Buenos dias”)

case “Italian”: print(“Buogiorno”)

default: print(“Aucune idée”)

}

A noter que le Switch est case sensitive, une majuscule mal placée nous fera pas rentrer dans le cas.

Nous pouvons aussi combiner les valeurs sur un cas si le code est identique:

let region = “paca”

 

switch region.uppercased() {

case “PACA”: print(“Sudiste”)

case “CORSE”: print(“Sudiste”)

case “OCCITANIE”: print(“Sudiste”)

case “NOUVELLE AQUITAINE”: print(“Sudiste”)

default: print(“C’est le Noooord”)

}

 

// peut être écrit comme ceci

 

switch region.uppercased() {

case “PACA”, “CORSE”, “OCCITANIE”, “NOUVELLE AQUITAINE”: print(“Sudiste”)

default: print(“C’est le Noooord”)

}

 

 

le guard vérifie une condition, si celle ci est remplie, le code suivant les accolades du guard sera effectué, sinon, nous effectuerons le code entre accolades et sortirons de la fonction avec le mot clé return. Les guard sont toujours dans des fonctions, les fonctions seront abordées dès la section suivante.

let int = 30

 

func check() {

    guard int < 10 else {

        print(“Too big”)

        return

    }

    print(int)

}

check()

 

Les ControlState statements (déclarations de contrôle de transfert en français) permettent d’influer sur le déroulement de notre code. Il en existe plusieurs:

  • continue
  • break
  • fallthrough
  • return (vu dans le guard)

Continue

Nous permet de dire à une boucle d’arreter se qu’elle fait et s’attaquer à la prochaine itération. En gros, nous disons. J’en ai fini avec ceci, on passe au suivant.

Exemple:

let classroomForGirls = [“Marie”: true, “Jean”: false, “Claude”: false, “Sylvie”: true, “Cathy”: true, “Myriam”: true, “Sylvain”: false, “Chris”: false]

var realClass: [String] = []

 

for (name, isGirl) in classroomForGirls {

    if !isGirl {

        continue

    }

    realClass.append(name)

}

 

print(realClass)

 

Nous voyons ici que si isGirl est false, le realClass.append(name) ne sera pas exécuté car avec le continue nous passons directement à l’itération suivante.

 

Break

Le break permet d’arrêter immédiatement l’éxecution d’un code entre accolades, cela peut être une condition

Exemple:

let luckyNumbers = [1, 3, 7, 9, 13, 15, 17]

 

for number in luckyNumbers {

    if number == 13 {

        break

    }

    print(number)

}

 

La boucle s’arrête dès que nous avons une correspondance (que number est égal à 13).

Nous pouvons aussi utiliser le break dans le switch:

let n = 4

 

switch n {

case 1: print(n)

case 2: print(n)

case 3: print(n)

default: break

}

 

Le fallthrough

Dans certains langages, nous devons mettre un break a la fin de chaque cas dans un switch, pout ne pas à passer à travers tous les cas une fois une correspondance trouvée. Avec Swift, ce n’est pas le cas, nous sortons de notre switch une fois le cas trouvé.

Le Fallthough permet de tomber aussi dans le cas suivant si la condition a été trouvée. Cela peut être un cas ou un défaut

let bay = “La Ciotat”

var fallPhrase = “La baie de \(bay)”

switch bay {

case “La Ciotat”:

    fallPhrase += ” a été élue plus belle baie du monde et”

    fallthrough

default: fallPhrase += ” est en france”

    

}

 

print(fallPhrase)

 
 

Les conditions peuvent aussi servir à déballer un optionnel de façon sûre sans avoir de risque de crash.

Nous pouvons utiliser les if ou les guard

exemples.

//1. if else pour déballer un optionnel avec ‘!’

if optional != nil {

    print(optional!)

} else {

    print(“cette valeur est nil”)

}

 

//2. if else pour déballer un optionnel en tentant de créer une constante à partir de cet optionnel

if let nonOptional = optional {

    print(nonOptional)

} else {

    print(“cette valeur est nil”)

}

//Nous essayons ici de créer une constante avec l’optionnel, si l’optionnel est nil, la constante ne sera pas créée et nous passerons dans le else

 

//3. guard pour déballer un optionnel avec ‘!’

func unwrapOptional() {

    guard optional != nil else { return }

    print(optional!)

}

 

//4. guard pour déballer un optionnel en tentant de créer une constante à partir de cet optionnel

func createNonOptional() {

    guard let nonOptional = optional else { return }

    print(nonOptional)

}

//Nous essayons ici de créer une constante avec l’optionnel, si l’optionnel est nil, la constante ne sera pas créée et nous passerons dans le else et return. Le code suivant ne sera donc jamais effectué

 

Conseil: Ne jamais déballer un optionnel si nous ne sommes pas sûr qu’il ait une valeur.

Les Fonctions

Une fonction est en morceau de code encapsulé qui effectue une tache précise et ne sera effectué que quand il sera appelé par son nom. Si une fonction n’est jamais appelée, alors le code présent à l’intérieur de cette fonction ne sera jamais lancé.

Une fonction va se composer de 5 éléments:

  • Le mot clé func
  • Le nom de la fonction suivi de parenthèses
  • Des paramètres à l’intérieur des parenthèses (optionnel)
  • Un type de valeur qui sera retourné précédé de ‘->’ (optionnel)
  • Le code a effectuer entre accolades {} si la fonction est appelée.

exemple:

func calculateEra(_ width: Int, _ height: Int) -> Int {

    return width * height

}

Ici nous avons un mot clé (func), un nom de fonction (calculateEra), des paramètres(width et height de type Int), un retour de type Int aussi.

Le code entre accolades est effectué et retourne l’aire de type int avec le mot clé return.

Appeler une fonction.

Une fois la fonction créée, elle peut être appelée pour que son code soit exécuté. Elle peut être appelée à tout moment et de multiples fois. 

 

 

Comme expliqué dans la définition, le code de la fonction n’est effectué que lorsque la fonction est appelée. Pour appeler une fonction, on procède de la même façon que pour une variable et on ajoute entre les parenthèses les valeurs de paramètres si la fonction en demande.

Exemples:

func maPremièreFonction() {

    let functionText = “salut les codeurs!”

    print(functionText)

}

 

maPremièreFonction()

 

Nous pouvons voir ici une fonction basique sans paramètres. Cette fonction est appelée et le code effectué lorsque nous écrivons  maPremiereFonction().

Nous allons voir ici les fonctions basiques, les fonctions n’utilisant ni paramètre, ni retour. Voici un exemple:

func sayHello() {

    print(“Salut les codeurs!”)

}

 

Notre fonction sans paramètre ni retour est créé. Pour l’appeler:

sayHello()

 

Nous obtenons ainsi dans la console: Salut les codeurs!.

Nous avons déjà utilisé une fonction avec paramètre dans cette documentation: la fonction print(). Faisons maintenant les nôtres. Chaque paramètre aura un nom suivi de ‘:’ et de son Type. 

Exemple:

func sayHelloTo(name: String) {

    print(“Salut “ + name)

}

 

Pour utiliser la fonction, nous devons appeler la fonction et y entrer le paramètre:

sayHelloTo(name: “Athena”)

Nous obtenons ainsi Salut Athena.

Si le nom du paramètre est tel que nous le voyons, il apparaîtra ainsi dans l’appel de la fonction. Si vous ne voulez pas voir apparaître le nom du paramètre, il devra être précédé de ‘_’ et d’un espace. 

Exemple:

func calculateTip(_ bill: Int) {

    let tip = bill / 10

    print(“Pourboire pour la serveuse = \(tip)”)

}

 

Le nom du paramètre n’apparaîtra pas lors de l’appel de la fonction:

calculateTip(234)

 

Les fonctions avec retour impliquent qu’au moment ou nous appelons une fonction avec retour, nous attendons de récupérer une valeur. Nous devons donc spécifier un type de retour et utiliser le mot clé return à l’intérieur de notre code pour retourner la valeur voulue. 

Le code à l’intérieur de la fonction suivant la déclaration du return ne sera pas effectué.

func calculateEra(_ width: Int, _ height: Int) -> Int {

    return width * height

    print(“On ne m’appelera pas, je suis après le retour”)

}

 

Nous pouvons ainsi désormais attribuer une valeur à une constante ou variable grâce au retour de notre fonction:

let era = calculateEra(5, 4)

print(“L’aire de mon bureau est de \(era) m2″)

 

 

La programmation orienté objet

En programmation, l’objet à plus ou moins la même définition que dans la vie de tous les jours. Par exemple un ordinateur, un clavier, un iPhone… Un utilisateur est aussi un objet en programmation. En fait, dans la programmation orienté objet, presque tout est un objet, et vous aller en utiliser tout au long de votre apprentissage dans la programmation.

Pour créer un objet, nous avons d’abord besoin, à l’image d’un architecte de créer un plan, un cahier des charges, ou un moule. Ce plan aura entre autre des propriétés, des méthodes qui seront autant de fonctionnalités que l’on attribuera aux objets. Ce ‘plan’ est soit une classe, soit une structure.
Une fois ce plan fait, nous pouvons initialiser des objets à l’infini. Chacun suivant son plan.

Dans une application, la classe ou la strucure peut être écrite dans un fichier séparé ou dans un fichier joint à d’autres éléments. Comparé à d’autres langages, nous n’avons pas besoin ensuite d’importer le fichier pour l’avoir disponible dans tous les autres fichiers.

Lorsqu’on parle d’objet, on peut entendre instance de classe. C’est la même chose.

Les structures et les classes ont ces points communs:

  • Des propriétés pour stocker des valeurs
  • Des méthodes pour ajouter des fonctionnalités
  • Des indices pour accéder aux valeurs en utilisant la syntaxe d ‘indices
  • Des constructeurs pour mettre en place l’état initial de la classe ou de la structure
  • Peuvent être étendus pour ajouter des fonctionnalités au delà de leur implémentation de départ
  • Se Conforment au protocole 

Par contre, les classes ont quelques petites choses en plus

  • L’héritage
  • Le Type casting pour vérifier et interpréter le type de classe
  • Le déinitialiseur, pour déconstruire un objet et libérer de l’espace
  • Le comptage de référence autorise plus d’une référence pour la classe

Au de la de ces quelques différences, les classes et les structures sont similaires

Pour définir une classe ou une structure, la même syntaxe est utilisée. Seul le mot clé changera: class pour classe et struct pour structure. La logique sera alors entre les accolades

Nous avions vu dans les bases les conventions de nomade pour les variables et les constantes. Pour les classes et les structures nous commencerons toujours par une majuscule pour le nom.

Pour la compréhension de ces sections, nous allons créer des objets du quotidien, qui seront suivis dans tous les chapitres de la POO: un ordinateur et une voiture.

class Ordinateur {

    //Ajout des propriétés

    //Ajout des méthodes

}

 
 struct Voiture {

    //Ajout des propriétés

    //Ajout des méthodes

}

 

La création d’une instance de classe peut aussi être appelée initialisation de l’objet. Nous créons en fait un objet à partir du plan classe ou structure que nous avons fait. 

//Création d’une instance de classe

var iMac = Ordinateur()

 

//Création d’une instance de structure

var maJolieVoiture = Voiture()

 

Nous pouvons voir que nous avons désormais une variable qui contient notre objet. La valeur de la variable ajoutée est le nom de notre classe suivie de parenthèses. Elles sont vides ici car nous n’avons pas encore créé de constructeur personnalisé. Nous y viendrons très vite.

Les propriétés sont des variables qui vont définir des caractéristiques communes à tous les objets créés par cette classe ou struct. Ils pourront avoir des valeurs différentes bien évidemment mais ils devront posséder ces caractéristiques.

Notre classe ordinateur. Qu’on les ordinateurs en commun? Disons une marque, un modèle, une année, un processeur, une ram, une définition d’écran, un disque dur…. Ajoutons cela comme des propriétés. Voila ce que cela donne.

class Ordinateur {

    //Ajout des propriétés

    var marque: String = “Apple”

    var modèle: String = “iMac 27”

    var année: Int = 2019

    var processeur: String = “Core i7”

    var ram: Int = 16

    var stockage: Int = 256

    var défintion: (Int, Int) = (4000, 2000)

    //Ajout des méthodes

}

Désormais, nous pouvons accéder aux propriétés via notre objet créé. Pour ceci, nous ajoutons un ‘.’ Après notre objet puis le nom de la propriété voulue.

print(iMac.marque)

//Apple

Faisons pareil sur la structure. La voiture va avoir une marque, un modèle, une année,  une couleur…

struct Voiture {

    //Ajout des propriétés

    var marque: String = “Toyota”

    var modèle: String = “Yaris”

    var année: Int = 2018

    var kms: Int = 20150

    var couleur: String = “Gris”

    //Ajout des méthodes

}

Nous pouvons aussi modifier les valeurs de ces dernières, après tout ce sont des variables.

iMac.année = 2017

print(iMac.année)

//2017

 

maJolieVoiture.couleur = “bleu”

print(maJolieVoiture.couleur)

//Bleu

Ce sont des propriétés qui ne stockent aucune valeur, elles possèderont cependant un getter et un setter pour obtenir des mettre en place des valeurs.

Commencons avec le getter: 

 

struct Voiture {

    //Ajout des propriétés

    var marque: String = “Toyota”

    var modele: String = “Yaris”

    var année: Int = 2018

    var kms: Int = 20150

    var couleur: String = “Gris”

 

    var kmsString: String {

        get {

            return “Nombre de kilomètres: \(kms)”

        }

    }

    //Ajout des méthodes

 

}

 

var maJolieVoiture = Voiture()

print(maJolieVoiture.kmsString)

//Nombre de kilomètres: 20150

 

cette variable ne contient pas de valeur, nous savons juste qu’elle sera de type string. Lorsqu’elle sera appelée, nous allons effectuer le code dans le get (mot clé pour obtenir) et nous retournerons la valeur voulue. 

Si nous n’avons pas de set, le mot clé get est optionnel. nous retournerons uniquement la valeur voulue:

class Ordinateur {

    //Ajout des propriétés

    var marque: String = “Apple”

    var modele: String = “iMac 27”

    var année: Int = 2019

    var processeur: String = “Core i7”

    var ram: Int = 16

    var stockage: Int = 256

    var défintion: (Int, Int) = (4000, 2000)

    //Ajout des méthodes

 

    var completeName: String {

        return marque + ” “ + modele

    }

} 

 

Dvar iMac = Ordinateur()

print(iMac.completeName)

 

//Apple iMac 27

 

Avec le setter maintenant, nous allons utiliser le mot clé set et entre parenthèses sera notre nouvelle valeur. Pour définir une valeur à une propriété donnée.

class Ordinateur {

    //Ajout des propriétés

    var marque: String = “Apple”

    var modele: String = “iMac 27”

    var année: Int = 2019

    var processeur: String = “Core i7”

    var ram: Int = 16

    var stockage: Int = 256

    var défintion: (Int, Int) = (4000, 2000)

    //Ajout des méthodes

 

    var completeName: String {

        return marque + ” “ + modele

    }

 

    var ramComputed: String {

        get {

            return \(ram)”

        }

        set(newValue) {

            ram = Int(newValue) ?? ram

        }

    }

}

 

La variable ramComputed est en String, mais j’aurais très bien pu la définir en tant que Int directement. Ce qui nous donne:

var iMac = Ordinateur()

iMac.ramComputed = “32”

print(“Nouvelle ram ajoutée: \(iMac.ram)”)

 

 

C’est très bien ceci, mais cela est il bien utile étant donné que nos propriétés stockées font exactement la même chose? Cela nous permet  plusieurs choses:

  • Personnaliser la donnée reçue, par exemple pour le nombre de kilomètres.
  • Obtenir des données différentes des propriétés. Par exemple obtenir un pointX ou Y à partir d’un cadre de vue, ou son centre.
  • Définir des propriétés comme privées et ajouter de la sécurité au code. Par toutes les propriétés pourront être modifiées et lues et sous certaines conditions. 

En ajoutant private à une propriété ou une méthode, nous la rendons accessible uniquement à l’intérieur de sa classe ou struct. Cela nous permet d’avoir une certaine sécurité et de ne pouvoir modifier des données que si nous le voulons. Par exemple, il est possible de lire et modifier la valeur du nombre de kms de notre voiture. C’est bien, mais dans la pratique, nous ne pouvons qu’ajouter des kms à une voiture, pas modifier le compteur pour la revendre plus cher. Hors notre application ne permet pas cela. Changeons cela en private et ajoutons un getter et setter

struct Voiture {

    //Ajout des propriétés

    var marque: String = “Toyota”

    var modèle: String = “Yaris”

    var année: Int = 2018

    private var _kms: Int = 20150

    var couleur: String = “Gris”

 

    var kms: Int {

        get {

            return _kms

        } set(newValue) {

            if newValue > _kms {

                _kms = newValue

            } else {

                print(“Coquin tu essaies de modifier ton compteur”)

            }

        }

    }

    //Ajout des méthodes

}

Nous voyons que le mot clé private ne nous donne plus accès à la variable _kms. J’ai ajouté un ‘_’ devant le nom de la variable privée. C’est une convention pour pouvoir voir au premier coup d’oeil une variable privée. 

Maintenant essayons de modifier les valeurs

var maJolieVoiture = Voiture()

 

print(maJolieVoiture.kms)

//Nombre de kilomètres: 20150

maJolieVoiture.kms += 15

print(maJolieVoiture.kms)

//Nombre de kilomètres: 20165

maJolieVoiture.kms -= 200

//Coquin tu essaies de modifier ton compteur

print(maJolieVoiture.kms)

//Nombre de kilomètres: 20165

 

Nous pouvons ainsi voir l’intérêt de privatiser les propriétés.

Comme leur nom l’indique, ces propriétés observent répondent à un changement de valeur. Il est appelé à chaque fois qu’une valeur lui est définie, même si c’est la même. Nous pouvons observer 2 choses:

  • willSet, avant que la valeur soit stockée.
  • didSet, une fois que la valeur est stockée.

Pour voir ceci, ajoutons une souris comme propriété de notre ordinateur

class Ordinateur {

    //Ajout des propriétés

    var marqueString = “Apple”

    var modeleString = “iMac 27”

    var annéeInt = 2019

    var processeurString = “Core i7”

    var ramInt = 16

    var stockageInt = 256

    var défintion: (IntInt) = (40002000)

 

 

    var completeNameString {

        return marque + ” “ + modele

    }

 

    var ramComputedString {

        get {

            return \(ram)”

        }

        set(newValue) {

            ram = Int(newValue) ?? ram

        }

    }

 

    var mouseString = “Aucune”{

        willSet(newMouse) {

            print(“Je vais installer cette souris: ” + newMouse)

        }

        didSet {

            print(“Avant j’avais ” + oldValue + ” comme souris”)

            print(“Maintenant j’ai cette souris: ” + mouse)

        }

    }

 

    //Ajout des méthodes

}

 

var iMac = Ordinateur()

iMac.mouse = “Magic mouse 2”

//Je vais installer cette souris: Magic mouse 2

//Avant j’avais Aucune comme souris

//Maintenant j’ai cette souris: Magic mouse 2 
 
Regardons comment cela fonctionne. willSet prend entre parenthèses la valeur que l’on va mettre.
DidSet contient une oldValue qui est l’ancienne valeur, ainsi que sa valeur qui vient d’être mise en place. Ou ai-je trouvé oldValue? Je ne l’ai écrit nulle part, cette variable est présente dans le didSet. Cela nous permet de faire des vérifications.

Les méthodes ont exactement la même syntaxe et la même utilisation que les fonctions.

Exemple

class Ordinateur {

    //Ajout des propriétés

    var marque: String = “Apple”

    var modele: String = “iMac 27”

    var année: Int = 2019

    var processeur: String = “Core i7”

    var ram: Int = 16

    var stockage: Int = 256

    var défintion: (Int, Int) = (4000, 2000)

 

 

    var completeName: String {

        return marque + ” “ + modele

    }

 

    var ramComputed: String {

        get {

            return \(ram)”

        }

        set(newValue) {

            ram = Int(newValue) ?? ram

        }

    }

 

    var mouse: String = “Aucune”{

        willSet(newMouse) {

            print(“Je vais installer cette souris: ” + newMouse)

        }

        didSet {

            print(“Avant j’avais ” + oldValue + ” comme souris”)

            print(“Maintenant j’ai cette souris: ” + mouse)

        }

    }

 

    //Ajout des méthodes

 

    func turnOn() {

        print(“ordinateur allumé”)

    }

 

    func turnOff() {

        print(“ordinateur éteint”)

    }

 

    func changeStorage(capacity: Int) {

        stockage = capacity

    }

}

 

Nous avons donc ici une méthode pour allumer l’ordinateur, pour l’éteindre et pour changer la capacité de stockage.

Pour les appeler, c’est comme si vous appeliez une fonction après le nom de l’objet puis ‘.’

iMac.turnOn()

iMac.turnOff()

iMac.changeStorage(capacity: 512)

 

Sur une structure, nous devrons ajouter le mot clé mutating, car les variables ne sont pas modifiables au sein de leur propre initialiseur. J’ai une voiture hybride qui passe en moteur essence à une certaine vitesse. Créons une fonction pour changer de type de moteur et ajouter un kilométrage.

struct Voiture {

    //Ajout des propriétés

    var marque: String = “Toyota”

    var modèle: String = “Yaris”

    var année: Int = 2018

    private var _kms: Int = 20150

    var couleur: String = “Gris”

    var electric = true

 

    var kms: Int {

        get {

            return _kms

        } set(newValue) {

            if newValue > _kms {

                _kms = newValue

            } else {

                print(“Coquin tu essaies de modifier ton compteur”)

            }

        }

    }

    //Ajout des méthodes

    mutating func drive(speed: Int) {

        electric = speed < 70

        kms += 1

    }

}

 

Nous ne voulons pas définir des valeurs par défaut à nos classes. Pourquoi? Car ces valeurs seront différentes à chaque fois. Vous n’aurez pas toujours le même mac avec la même configuration ou la même voiture de la même couleur avec le même kilométrage.

Pour cela nous avons des Constructeurs, définis par le mot clé init qui nous permet de créer des objets avec des valeurs personnalisées.

Nous allons commencer par supprimer les valeurs par défaut. j’ai aussi volontairement réduit les propriétés pour clarifier au mieux:

class Ordinateur {

    var marque: String

    var modele: String

    var ram: Int

    var stockage: Int

}

A ce  moment la, une erreur apparaît, disant que nous n’avons pas d’initialiseur, ou de constructeur.

class Ordinateur {

    var marque: String

    var modele: String

    var ram: Int

    var stockage: Int

 

    init(marque: String, modele: String, ram: Int, stockage: Int) {

        self.marque = marque

        self.modele = modele

        self.ram = ram

        self.stockage = stockage

    }

}

Notre Constructeur est fait, les noms des paramètres dans le init sont explicitement les même que les noms des propriétés pour bien comprendre de qui correspond à qui. Ensuite, j’attribue les valeurs aux propriétés correspondantes.

Le self signifie soi-même, la propriété ou variable dite de ‘top level’ à la base de la classe. Dans ce case, ce sont nos propriétés. Sans le self, il y aurait confusion entre le nom du paramètre et la propriété.

Maintenant, si je veux créer un objet, je devrai utiliser cet init. Vous remarquerez

que dès l’ouverture des parenthèses, l’auto complétion agit.

var macbook = Ordinateur(marque: “Apple”, modele: “Macbook pro”, ram: 16, stockage: 128)

 

Passons aux structures maintenant. Si j’enlève les valeurs par défaut. Il n’y a pas d’erreur. La structure crée automatique son init avec les valeurs dont elle a besoin.

struct Voiture {

    //Ajout des propriétés

    var marque: String

    var modèle: String

    var année: Int

    var kms: Int

    var couleur: String

}

Et lors de la création de l’objet, notre init est bien là:

var punto = Voiture(marque: “Fiat”, modèle: “Punto Evo”, année: 2012, kms: 120000, couleur: “Jaune”)

 

Tout comme l’héritage entre êtres vivants, les classe ont aussi un héritage, on appelle cela aussi des sous classes. L’héritage signifie que la sous classe ou classe enfant hérite des propriétés et méthodes de sa classe mère mais dispose en plus de ses propres propriétés et méthodes.

Prenons l’exemple de notre ordinateur. il avait une marque, un modèle, une ram, un stockage

class Ordinateur {

    var marque: String

    var modele: String

    var ram: Int

    var stockage: Int

    init(marque: String, modele: String, ram: Int, stockage: Int) {

        self.marque = marque

        self.modele = modele

        self.ram = ram

        self.stockage = stockage

    }

}

Prenons maintenant un ordinateur portable, il aura les mêmes propriétés mais en plus il aura une autonomie par exemple. Au lieu de refaire toute une classe nous allons faire hériter le portable de Ordinateur

class Macbook: Ordinateur {

    var autonomie: Int

    init(marque: String, modele: String, ram: Int, stockage: Int, autonomie: Int) {

        self.autonomie = autonomie

        super.init(marque: marque, modele: modele, ram: ram, stockage: stockage)

    }

}

Nous pouvons voir que nous n’avons pas à réécrire toutes les propriétés de base mais que dans l’init, nous devons bien toutes les ajouter en paramètres. Ensuite nous pouvons donner une valeur à autonomie et avec le mot clé super, initialiser sa super classe ou sa classe mère.

La classe héritante peut accéder donc à toutes les méthodes et propriétés de la classe mère et avoir les siennes.Pour faire hériter d’un objet, on ajoute : puis le nom de la classe mère après le nom

class Macbook: Ordinateur {

    var autonomie: Int

    init(marque: String, modele: String, ram: Int, stockage: Int, autonomie: Int) {

        self.autonomie = autonomie

        super.init(marque: marque, modele: modele, ram: ram, stockage: stockage)

    }

    func use() {

        autonomie -= 1

    }

}

Exemple, l’ajout d’une méthode use() pour enlever de la batterie. Un objet de type Macbook pourra l’utiliser, mais pas un objet de la classe Ordinateur.

Override

On peut aussi changer du code dans une méthode avec le mot clé override

class Ordinateur {

    var marque: String

    var modele: String

    var ram: Int

    var stockage: Int

    init(marque: String, modele: String, ram: Int, stockage: Int) {

        self.marque = marque

        self.modele = modele

        self.ram = ram

        self.stockage = stockage

    }

    func useInTrain() {

        print(“Non, votre ordinateur est sur le bureau”)

    }

}

class Macbook: Ordinateur {

    var autonomie: Int

    init(marque: String, modele: String, ram: Int, stockage: Int, autonomie: Int) {

        self.autonomie = autonomie

        super.init(marque: marque, modele: modele, ram: ram, stockage: stockage)

    }

    func use() {

        autonomie -= 1

    }

    override func useInTrain() {

        print(“C’est parti”)

    }

}

Ici nous avons une méthode pour utiliser l’ordinateur dans le train. Selon si nous avons un ordinateur ou un Macbook, la méthode sera la même mais pas le résultat.

var iMac = Ordinateur(marque: “Apple”, modele: “iMac”, ram: 16, stockage: 128)

var macbook = Macbook(marque: “Apple”, modele: “Macbook pro”, ram: 16, stockage: 128, autonomie: 80)

macbook.use()

macbook.useInTrain()

//C’est parti

iMac.useInTrain()

//Non, votre ordinateur est sur le bureau

Les Extensions ajoutent de nouvelles fonctionnalités à des classes, structures et énumérations, que ce soient les votres ou pas.

En Swift, les extensions peuvent: 

  •  Ajouter des propriétés calculées d’instance et type
  • Définir des méthodes d’instance et de type
  • Créer de nouveaux constructeurs
  • Conformer un type à un protocole
  • ..
Déclaration d’une extension:
 

class MyClass {

 

}

 

extension MyClass {

 

}

 

J’ai ici créé une classe et créé une extension. Sa structure est la même que la classe. Le mot clé d’une extension est ‘extension’. Nous pouvons aussi ajouter des extensions à un type existant:

extension Int {

 

}

 
 Ajout de propriétés calculées:

 

Prenons par exemple notre extension de Int, nous allons y ajouter des propriétés calculées, pour convertir les secondes en minutes et en heures

extension Int {

    var sec: Int { return self }

    var min: Int { return self / 60 }

    var hour: Int { return self / 3600 }

}

 

let seconds = 135682

let minutes = seconds.min

let hours = seconds.hour

print(“dans notre constante seconds il y a \(seconds) secondes, \(minutes) minutes et \(hours) heures.”)

//dans notre constante seconds il y a 135682 secondes, 2261 minutes et 37 heures.

 

 

Nous pouvons aussi ajouter une valeur calculée qui ne sera pas du même type bien évidemment: 

extension Int {

    var toString: String {

        let hours = self / 3600

        let remainHours = self % 3600

        let minutes = remainHours / 60

        let seconds = remainHours % 60

        return\(hours) heures, \(minutes) minutes, \(seconds) secondes”

    }

}

 

let seconds = 3769

print(seconds.toString)

//0 heures, 2 minutes, 49 secondes

 

Vous pouvez aussi ajouter des méthodes à une extension:

 

extension Int {

    func toDouble() -> Double {

        return Double(self)

    }

}

 

let seconds = 39

print(seconds.toDouble())

//39.0

 

Nous pouvons aussi créer un constructeur dans une extension. Disons que nous voulons créer un autre init pour notre ordinateur. C’est une classe, nous aurons besoin d’un convenience init

class Ordinateur {

    var marque: String

    var modele: String

    var ram: Int

    var stockage: Int

    init(marque: String, modele: String, ram: Int, stockage: Int) {

        self.marque = marque

        self.modele = modele

        self.ram = ram

        self.stockage = stockage

    }

}

 

extension Ordinateur {

 

    convenience init(iMacWithRam ram: Int, stockage: Int) {

        self.init(marque: “Apple”, modele: “iMac”, ram: ram, stockage: stockage)

    }

}

 

let imac = Ordinateur(iMacWithRam: 16, stockage: 512)

 

Passons aux structures, nous pouvons créer notre propre init en plus de ce qui nous est créé automatiquement

 

struct Couleur {

    var red: Float

    var green: Float

    var blue: Float

    var alpha: Float

 

}

 

extension Couleur {

 

    init(dict: [String: Float]) {

        let red = dict[“red”] ?? 0

        let green = dict[“green”] ?? 0

        let blue = dict[“blue”] ?? 0

        self.init(red: red, green: green, blue: blue, alpha: 1)

    }

}

 

let newColor = Couleur(dict: [“red”: 0.4, “green”: 0.34, “blue”: 1]

 

J’ai ici une structure qui permet de créer une couleur, je veux changer mon init par rapport à un dictionnaire. C’est possible. On peut faire ceci sur des types déjà existants.

 

Nous pouvons aussi utiliser les extensions pour bien séparer les protocoles et ainsi permettre à la classe de se conformer à un protocole. Nous voyons les protocoles dans le prochain chapitre.

 

Définition

Comme son nom l’indique, l’énumération permet de grouper et énumérer des valeurs de façon sûre dans votre code. Chaque élément d’une énumération est un cas.

En Swift, il n’est pas obligatoire de donner une valeur à chacun des cas. Les valeurs peuvent être de différents types (Int, Double, Float, String, Character).

Syntaxe

Une Enumération ressemble dans sa construction à une classe ou une structure et se définit par un mot clé ‘enum’. Ce mot clé est suivi de du nom de l’Enum, selon la même convention que les classes (Commence par une majuscule) et les cas sont énumérés entre accolades. Chaque cas est introduit par le mot clé case

enum UserType {

    case admin

    case visitor

    case freeUser

    case paidUser

}

 

Vous pouvez aussi énumérer les cas sur une ligne simple. Dans ce cas, le mot clé apparaîtra au début, et chaque cas sera séparé par une virgule.

enum Media {

    case photo, link, video, gif

}

 

Utilisation d’un enum

Si le type n’est pas défini, vous devrez utiliser le nom de l’enum, suivi d’un point et du cas.

var user = UserType.freeUser

 

Si le type est défini, le point suivi du cas suffira.

var user: UserType = .freeUser

 

Le Switch et les Enum

Lorsque nous avons vu les switch, nous devions donner une valeur par défault, si aucun des cas ne correspondait. Avec les Enum, si nous passons en revue tous les cas, le défaut ne sera pas obligatoire, car notre déclaration sera exhaustive.

switch media {

case .photo: print(“Vous avez ajouté une vidéo”)

case .link: print(“Voici le lien vers un site”)

case .gif: print(“J’adore les gifs”)

case .video: print(“Sortez le pop corn”)

}

 

Par contre, si nous n’enumérons pas tous les cas, une valeur par défaut sera obligatoire.

RawValues

Il est possible d’attribuer des valeurs à chaque cas. Pour ceci, il faut définir le type de valeur après le nom de l’enum et associer une valeur correspondante au type à chaque cas.

enum UserType: String {

    case admin = “Administrateur”

    case visitor = “Visiteur”

    case freeUser = “Utilisateur gratuit”

    case paidUser = “Utilisateur payant”

}

 

let newUser = UserType.paidUser.rawValue

print(newUser)

//Utilisateur payant

 

Les RawValues Implicites

Lorsque nous voulons associer des rawValues à des Int ou des String, nous ne sommes pas obligés de donner une valeur à chaque cas, elles sont implicitement crées.

enum UserType: String {

    case admin

    case visitor

    case freeUser

    case paidUser

}

 

let newUser = UserType.paidUser.rawValue

print(newUser)

//paidUser

 

Pour les Int, la rawValue sera comme l’index d’un array, il commencera de 0 (sauf explicitement défini autrement). Pour les String, nous aurons le nom du cas en String.

 

enum Media: Int {

    case photo, link, video, gif

}

 

let mediaChosen = Media.link

print(mediaChosen.rawValue)

//1. L’index de link est 1

 

enum Media: Int {

    case photo = 4, link, video, gif

}

 

let mediaChosen = Media.link

print(mediaChosen.rawValue)

//5

 

Initialiser une RawValue

Si vous énumérer possède un rawValue, il est possible d’initialiser un cas par rapport à sa rawValue.

Cependant, vous aurez une valeur optionnelle et peut être nil.

 

enum Media: Int {

    case photo, link, video, gif

}

 

let mediaToFind = Media(rawValue: 2)if mediaToFind != nil {

    print(“Nous avons trouvé”)

}

 

 

 

CaseIterable

Pour certaines énumérations, il peut être très utile d’avoir une collection de tous les cas. Pour ceci, il faut ajouter ‘: CaseIterable’ entre le nom de l’enum et les accolades. 

Ce : CaseIterable est un protocole. Nous parlerons des protocoles plus loin dans la documentation.

Ensuite, un simple nom de l’enum suivi de ‘.allCases’ permet de récupérer tout cet enum sous forme de collection.

enum UserType: String, CaseIterable {

    case admin

    case visitor

    case freeUser

    case paidUser

}

 

let allTypes = UserType.allCases

allTypes.forEach { (type) in

    print(type.rawValue)

}

 

/*

 admin

 visitor

 freeUser

 paidUser

 */

 

 

Les protocoles

Un protocole définit un plan de méthodes, propriétés et autres exigences pour une tache définie ou une fonctionnalité. Le protocole peut être utilisé pour une classe, une structure ou une énumération. Ces protocoles permettent ainsi l’implémentation des exigences. Une fois que les exigences sont satisfaites, on dit qu’il est conforme au protocole.

En plus des exigences, il est possible d’étendre un protocole à des fonctionnalités optionnelles.

 

Structure d’un protocole:

Créer un protocole est comme créer une classe ou un structure, seul le mot clé change: protocole. Nous pouvons ensuite l’attribuer à une classe en ajoutant : puis le nom du protocole.

protocol MonProtocole {

    

}

 

class MaClasse: MonProtocole {

    

}

 

Un protocole peut avoir des exigences de propriétés. Elles peuvent être de n’importe quel type. Nous devons spécifier comme pour une propriété calculée si elle set set get ou les 2.

J’ai donc créé 2 classes, une classe oiseau et une classe avion. Comme les 2 peuvent voler, j’ai décidé de créer un protocole voler. Ajoutons maintenant une propriété qui sera type d’ailes.

protocol Voler {

    var typeAiles: String { get set }

}

 

class Oiseau: Voler {

 

}

 

class Avion: Voler {

 

} 

 

Nous avons désormais 2 erreurs car nos classes ne se conforment pas aux exigences du protocole.

 

class Oiseau: Voler {

    var typeAiles: String = “Plumes”

}

 

class Avion: Voler {

    var typeAiles: String = “Acier”

}

 

Maintenant nos 2 classes se conforment au protocole.

En plus d’avoir des exigences de propriété, un protocole peut avoir des exigences de méthodes. Mais pourquoi? Reprenons l’exemple de notre oiseau et de notre avion. Tous 2 se conforment au protocole Voler. Pour ne pas oublier des méthodes et des propriétés obligatoire à voler, nous avons des exigences. La première était un type d’ailes. Nous pouvons avoir des méthodes exigées pour voler comme planer, décoller, atterri. Les 2 objets le font . Ajoutons les

protocol Voler {

    //Propriétés

    var typeAiles: String { get set }

    

    //Méthodes

    func planer()

    func decoller()

    func atterir()

}

 

class Oiseau: Voler {

    var typeAiles: String = “Plumes”

    

    func decoller() {

        //Regard a gauche et a droite

        //Battement d’ailes

    }

    

    func planer() {

        //Observer le paysage

    }

    

    func atterir() {

        //Faire attention a bien évaluer le sol

        //Rentrer les ailes

    }

}

 

class Avion: Voler {

    var typeAiles: String = “Acier”

    

    func decoller() {

        //Lecture des consignes de sécurité

        //Dégagement de la piste

        //Décollage

        //Beaucoup de bruit

    }

    

    func planer() {

        //servir boissons

        //regarder un film

    }

    

    func atterir() {

        //Attacher les ceintures

        //Applaudir le pilote

    }

}

 

Nos 2 objets ont du implémenter ces 2 méthodes, avec des choses bien différentes à l’intérieur, mais ce sont des méthodes essentielles pour voler