Revenir

Entre ton email pour recevoir le guide complet pour apprendre Swift peu importe ton niveau

Apprendre Swift - Les Bases (2/2)

Avant de commencer …

Si vous n’avez pas lu la première partie, je vous encourage vivement à le faire pour mieux comprendre l’article.

Voici le lien : Partie 1. Si c’est fait, c’est partit !

Les Tableaux

Je vous en avait parlé et j’avais dit que nous y reviendrions et nous y sommes.

Dans la partie sur les variables j’avais dit qu’on pouvait les voir comme un bout de papier sur lequel on note une information.

Les tableaux, sont un type particulier car ils contiennent ces variables, comme une pochette plastique qui contiendrait ces bouts de papier.

Un tableau possède des clés et des valeurs. Les clés commencent à 0.

Les valeurs sont toutes du même type.

À chaque clé correspond sa valeur. Tout comme chaque clé a une serrure spécifique.

Voici comment les créer :

let names : [String] = ["bob", "dylan", "jacques"]
// ou plus simplement :
let names2 = ["moi", "lui", "nous"]

// ou encore :
var ages = [Int]() // ça donnera un tableau d'entiers qui est vide
ages.append(58) // j'ajoute la valeur 58 à la fin du tableau

// on peut aussi ajouter à la fin du tableau de cette manière :
ages += [45]

Pour récupérer tout leur contenu on utilise les boucles :

// Récupérer le contenu :
let firstName = names[0] // on récupère le premier élément du tableau names
print(firstName)

// ou si je veux remplacer un certain élément du tableau :
var names2 = ["moi", "lui", "nous"]
names2[2] = "jean" // je modifie le troisième élément du tableau

// si je veux parcourir le tableau et afficher toutes les valeurs:
for name in names2 {
   print(name)
}

// si je veux la clé aussi je dois faire une énumeration :
for (key, name) in names.enumerated() {
    print(“\(key) : \(name))
    // cette syntaxe permet de mettre une variable dans une chaine de caractères. On appelle ça l'interpolation.
}

Pour finir, on a aussi des tableaux particuliers : des dictionnaires.

Les dictionnaires sont comme des tableaux à la seule différence que les clés ne sont pas définies par défaut comme étant des nombres : on peut mettre ce qu’on veut dans les clés.

Par exemple, si on veut que les clées soient des String on peut le faire.

// un dictionnaire :
let aeroports: [String: String] = ["CDG": "Charles de Gaulle", "ORY": "Orly"]
// on peut aussi faire sans les types :
let aeroports2 = ["MRS": "Marseille", "LYS": "Lyon"]

// on récupère la valeur du dictionnaire pour la clé "ORY":
let orly = aeroports["ORY"]!
print(orly)

// et on les parcourt de la même manière que précédemment avec les boucles (dans un dictionnaire pas besoin d'enumerer)
for (code, ville) in aeroports {
  print("\(code) correspond à l'aeroport de la ville de \(ville)")
}

Vous avez énormément de possibilités avec les tableaux.

Il y a des fonctions pour tout (comme append par exemple). Je vous laisse regarder dans la documentation d’Apple car vous en aurez forcément besoin un jour

Globalement, on utilise les tableaux pour stocker plusieurs valeurs qui ont un lien entre elles contrairement à une variable classique qui ne contient qu’une valeur.

Les dictionnaires, eux, sont utilisés dans le même cadre que les tableaux quand on a besoin d’avoir une clé particulière pour chaque valeur.

Les Classes

Si vous avez suivi les premiers articles sur les bases en Swift, vous avez pas mal de connaissances qui vous permettront de faire de bonnes choses.

Cependant, il vous manque une partie importante.

Pour découvrir la programmation orienté objet, partons d’un problème :

Comment stocker des informations sur quelque chose de complexe comme une personne, une table ou autre objet, un chien, etc ?

Voici la première solution :

let name1 = "John"
let age1 = 29
let gender1 = "Male"

Très bien, et si j’ai 2 personnes ?

let name1 = "John"
let age1 = 29
let gender1 = "Male"
let city1 = "Las Vegas"
let height1 = 1.85

let name2 = "Tony"
let age2 = 45
let gender2 = "Male"
let city2 = "Tokyo"
let height2 = 1.69

Ok, et si j’en ai 10 ? 20 ? 100 ? 1 000 ?

Vous voyez le problème ? Voilà pourquoi la programmation orienté objet a été inventée.

Avec la programmation orienté objet, on crée un type de variable qui va regrouper toutes les informations d’un objet.

Par exemple si je crée la classe Person je vais regrouper dedans : le nom de la personne, son age, son sexe…

Ainsi, chaque variable du type Person contiendra une variable, pour le nom,l’âge et le sexe.

Mais ce n’est pas tout !

Ce type peut aussi contenir des fonctions de la même manière.

Vocabulaire et infos sur la construction d’une classe :

Les variables d’une classe sont appelées propriétés et les fonctions des méthodes.

Lorsque l’on crée une variable à partir d’une classe on dit qu’on instancie la classe.

Une méthode particulière est appelée quand on instancie une classe : le constructeur. Elle a un nom particulier, vous verrez dans l’exemple. Elle peut ne pas être définie, mais si c’est le cas, vous ne pouvez pas définir de proriétés sans valeur prédéfinie.

Si on reprend l’exemple des personnes :

class Person {
    var name: String
    var age: Int
    var gender: String
    var city: String
    var height: Float
    
    // le constructeur
    init(name: String, age: Int, gender: String, city: String, height: Float) {
        // self.name corresponds à la variable juste au dessus de la déclaration du constructeur alors que name correspond à ce qu'il y a en paramètres du constructeur
        // Ainsi je dis que le nom de la personne est celui qui est passé en paramètres
        self.name = name
        self.age = age
        self.gender = gender
        self.city = city
        self.height = height
    }
}

let person1 = Person(name: "John", age: 29, gender: "Male", city: "Las Vegas", height: 1.85)
let person2 = Person(name: "Tony", age: 45, gender: "Male", city: "Tokyo", height: 1.69)

Beaucoup plus simple non ? Au premier abord, non. Mais en y réfléchissant bien et avec un peu de pratique vous verrez que oui.

Pour modifier ou accéder à une propriété, rien de plus simple, voici l’exemple :

// accéder à la valeur :
print(person1.age) // affichera 29

// modifier la valeur :
person1.age = 31
print(person1.age) // affichera 31

Maintenant qu’on a vu ça, je dois vous présenter quelque chose de similaire aux classes mais plus simple : Les structures

Les Structures

Pour faire simple, une structure c’est comme une classe sauf qu’elle n’a pas de constructeur. Il est généré automatiquement.

Et que fait ce constructeur généré automatiquement ? Il affecte ce que vous lui passez en paramètres aux différentes propriétés.

Par exemple, si je crée une structure Person dans laquelle je met les propriétés name, age et gender alors le constructeur va prendre en paramètres name, age et gender et affectera les valeurs passées en paramètres aux propriétés correspondantes.

Si je reprends le code plus haut et que je crée une structure à la place, voici le résultat :

struct Person {
    var name: String
    var age: Int
    var gender: String
    var city: String
    var height: Float

    // plus besoin de constructeur car celui qui est généré fait EXACTEMENT ce que j'ai fait dans le constructeur de la classe
}

let person1 = Person(name: "John", age: 29, gender: "Male", city: "Las Vegas", height: 1.85)
let person2 = Person(name: "Tony", age: 45, gender: "Male", city: "Tokyo", height: 1.69)

Autre différence avec les classes :

Si je déclare une classe Person et que je crée 2 variables à partir de cette classe : person1 et person2 et qu’ensuite je fais :

person2 = person1

alors quand je vais modifier une propriété de person1, la même propriété de person2 sera modifiée. Et inversement.

Modifier une instance modifie toutes celles qui lui sont égales.

On appelle ça un type par référence

Les structures sont des types par valeur.

Donc si on fait exactement la même chose avec des instances d’une structure, modifier l’une n’affectera pas l’autre.

Une dernière petite chose…

Des classes peuvent hériter d’autres classes ! C’est-à-dire qu’elles vont récupérer les méthodes et propriétés de la classe parente. Vous pourrez ensuite les redéfinir ou ajouter de nouvelles caractéristiques. Mais cela n’affectera en aucun cas la classe parente.

Voici comment faire :

class Vehicle {
    var speed = 0
    var numberOfPassengers = 0
    
    init(speed: Int, numberOfPassengers: Int) {
        self.speed = speed
        self.numberOfPassengers = numberOfPassengers
    }

    func move() {
        print("moving...")
    }
}

// Car et Bicycle héritent de Vehicle
class Car: Vehicle {
    init() {
        super.init(speed: 120, numberOfPassengers: 5)
        // appelle le constructeur parent
    }

    // redéfinis la méthode de la classe parente
    override func move() {
        print("vroom vroom")
    }
}

class Bicycle: Vehicle {
    // ajoute des propriétés mais n'affecte pas la classe parente
    var hasBasket = true

    override func move() {
        // appelle la méthode move de la classe parente
        super.move()
        // de la même manière, on peut récupérer les propriétés de la classe parente

        print("I am rinding my bike")
    }
}

Mais attention, ça ne marche qu’avec les classes pas les structures.

Les optionnels

Les optionnels sont une des spécificités de Swift. Très peu d’autres langages les utilisent.

Ils sont très utilisés donc c’est extrêmement important de comprendre comment ça marche.

Pour faire simple, les optionnels sont des types comme String, Int ou n’importe quel autre type sauf que la valeur est optionnelle.

Par exemple, si je veux créer une chaîne de caractères optionnelle, le type s’écrira comme ça : String?.

Et c’est pareil pour n’importe quel autre type.

Si aucune valeur est dans la variable de type optionnel, elle vaut nil.

On peut les voir comme une boîte dans laquelle il y aurait ou non quelque chose.

Voici un exemple d’utilisation :

var gift: String? = "Computer" // cette variable vaut « Computer »

var gift2: String? // cette variable vaut nil 

Il y a ensuite 2 manières d’accéder à la valeur d’un optionnel :

  • on peut le faire de manière « implicite » en ajoutant un ? après le nom de la variable quand on l’utilise
  • ou on peut le faire de manière « explicite » en ajoutant un ! après le nom de la variable quand on l’utilise
  • on peut le faire avec un if let ou un guard let ( je ferai un exemple )

La manière implicite renverra nil ou la valeur sans faire d’erreurs car la variable renvoyée sera toujours optionnelle tandis que la manière explicite accèdera à la valeur et la convertira en son équivalent non optionnel ce qui signifie que si la valeur est nil le programme essaierai de convertir cette valeur en un certain type ce qui est impossible. Donc votre code plantera.

Avec if let et guard let on va créer une nouvelle variable qui contiendra le type de la variable optionnelle.

Voici un exemple :

struct Gift {
    var content: String?
}

var gift1 = Gift() // on ne donne pas de valeur au constructeur donc content vaut nil car il est optionnel
var gift2 = Gift(content: "computer")

print(gift1.content!) // nil
print(gift2.content ?? "") // s'il n'y a pas de valeur, affiche ""

// si on accède aux propriétés de l'objet on doit utiliser ? ou !
// count est une propriété de la classe String qui renvoie le nombre de lettre de la String
print(gift1.content?.count)
print(gift2.content!.count) // j'utilise ! seulement quand je suis sûr à 100% d'avoir une valeur

if let content = gift1.content {
    // ici on a accès à la variable content qui contient la valeur de gift si elle en a une sinon cette condition est fausse et le programme ne viendra pas ici
    print(content)
}

guard let content = gift2.content else { return }
// pareil que pour le if let, on crée une nouvelle variable avec le contenu de gift2 si elle n’est pas nil sinon on le programme va exécuter le code qui est après le else

N’oubliez pas qu’un guard let devra toujours avoir un else et qu’il doit y avoir un return dedans.

Si vous voulez faire quelque chose de différent en fonction de si la variable est nil ou non utilisez un if let.

Sinon si vous devez absolument avoir une valeur dans votre optionnel et que s’il n’y en a pas ce n’est pas la peine de continuer d’exécuter la fonction, alors utilisez guard let.

On utilise principalement les optionnels avec les classes ou leurs propriétés

Avant de voir les exercices

Ce que vous venez de voir constitue un première introduction à Swift.

Si vous voulez aller plus loin…

Voici la liste d’articles que vous devez lire pour tout être prêt à créer des apps :

Le plus important étant celui sur les closures.

Ce n’est pas obligatoire pour la suite mais une fois que vous avez vu ça, vous connaîtrez parfaitement le langage Swift.

Vous pouvez maintenant apprendre le développement iOS sans être perdu !

Pour ça, j’ai créé une formation rien que pour toi.

J’ai imaginé la formation que j’aurais aimé avoir quand j’ai débuté.

Mais attention, ce n’est pas une formation comme les autres. Tu ne vas pas seulement recopier le code que j’écris.

Je vais t’expliquer les concepts de base du développement iOS pour que tu puisses créer tes propres apps tout seul à la fin de la formation.

À la fin de la formation, tu aura créé ta première application et tu aura une méthode pour créer des applications tout seul ainsi que toutes les bases pour y parvenir.

Mais ce n’est pas pour tout le monde. Il faut s’impliquer, travailler et faire l’effort de comprendre.

Je te laisse imaginer comment ça serait si tu étais capable de créer tes propres applications tout seul.

Imagine que tu n’aies besoin de personne ni d’aucune formation pour créer tes propres apps.

Tu as 2 choix maintenant.

Soit tu apprends le développement iOS avec les formations traditionnelles qui t’apprennent à recopier du code, soit tu apprends à créer tes applications tout seul grâce aux concepts de base et une méthode solide.

Tu es libre de rejoindre la formation ici :

Rejoindre la formation

Exercices

À présent, vous devez pratiquer sinon tout ça n’aura servi à rien.

D’abord essayez de faire quelques exos sur internet pour mettre ce qu’on a appris en pratique.

Ça vous aidera à retenir un peu tout ce qu’on a vu et ça vous permettra de comprendre les concepts de base du langage et de la programmation.

Évidemment, vous pouvez regarder le cours et chercher sur Internet quelques solutions mais pas le code entier. C’est bien mieux d’apprendere à chercher que de lire la solution.

Créez un playground où vous allez coder et si vous bloquez vraiment longtemps sans aucune piste, regardez les solutions, elles sont plus bas dans la page.

Essayez vraiment avant de regarder la solution, c’est important !

Si après avoir regardé la solutions vous vous rendez compte que votre code marche mais qu’il est différent du mien, c’est normal et c’est très bien !

Aucune solution n’est universelle, pour chaque problème en programmation il y a des milliers de possibilités pour le résoudre.

Petite aide pour résoudre des problèmes

Quand vous allez attaquer n’importe quel problème en programmation, ayez en tête ce que votre code doit faire à la fin.

Décomposez le problèmes en plusieurs petites étapes simples afin d’avancer petit à petit vers la solution.

Exercice 1

Créer une fonction qui prend en paramètres un tableau de Int et qui renvoie la valeur la plus haute du tableau.

Exercice 2

Créez un programme qui va parcourir les nombres entiers de 1 à 100 (inclus) et qui affichera “Fizz” pour chaque multiple de 3, “Buzz” pour chaque multiple de 5, “FizzBuzz” si c’est un multiple de 3 et 5 et le nombre lui-même sinon.

Exercice 3

CCréez une fonction qui va prendre en paramètre un tableau de String et qui va renvoyer le même tableau sans les éléments qui y sont en plusieurs fois. Il y a plein de méthodes pour le faire mais la plus simple est de créer un nouveau tableau qui sera le tableau filtré que la fonction renverra. Ensuite on parcourt le tableau passé en paramètre et si la String n’est pas dans le tableau créé précédemment alors on l’ajoute sinon on ne fait rien. Ainsi on ajoute toutes les String du tableau au nouveau tableau une seule fois donc plus d’éléments qui se répètent. Pour regarder si un tableau contient une valeur on utilise la méthode contains qui s’utilise sur un tableau : array.contains(element).

N’hésitez pas à chercher plus d’exos sur Internet pour vous entraîner davantage !

Si vous ne trouvez pas, les solutions sont plus bas dans la page.

Solutions

Solution exercice 1 :

func greatest(numbers: [Int]) -> Int {
  var max = numbers[0]

  for nb in numbers {
    if nb > max {
      max = nb
    }
  }

  return max
}

Solution exercice 2 :

for nb in 1...100 {
  if nb % 5 == 0 && nb % 3 == 0 {
    print("FizzBuzz")
  } else if (nb % 3 == 0) {
    print("Fizz")
  } else if (nb % 5 == 0) {
    print("Buzz")
  } else {
    print(nb)
  }
}

Solution exercice 3 :

func removeDuplicates(in array: [String]) -> [String] {
    var filtered: [String] = []
    for letter in array {
        if !filtered.contains(letter) {
            filtered.append(letter)
        }
    }
    return filtered
}

//pour tester :
let letters = ["a", "a", "b", "c", "c", "d", "e", "e"]
removeDuplicates(in: letters)