Le playground est un outil de développement intégré à Xcode qui permet d'écrire du code Swift et de voir les résultats en temps réel. Il est très utile pour tester des algorithmes ou des idées rapidement.
Pour ouvrir un playground, il suffit de cliquer sur "File" dans la barre de menu, puis "New" et enfin "Playground". Il est possible de choisir entre un playground vide ou un playground interactif.
Swift est un langage de programmation moderne, développé par Apple et présenté en 2014 lors de la WWDC (Worldwide Developers Conference). Créé pour remplacer Objective-C, il est puissant, facile à apprendre et inspiré de nombreux langages comme Python, Ruby et Rust. Swift est open source, ce qui le rend accessible à tous, et constitue la base idéale pour développer des applications dans l’écosystème Apple.
Swift propose trois types de commentaires :
// : Un commentaire classique pour des annotations
simples (aucun support de formatage).
//: : Un commentaire supportant le markup, souvent
utilisé pour documenter le code dans Xcode.
/* */ : Un commentaire multiligne pour des annotations
plus longues.
// Ceci est un commentaire classique
//: Ceci est un commentaire Swift supportant le markup
/* Ceci
est un
commentaire
multiligne */
Swift peut inférer automatiquement le type des variables et des constantes, mais il est également possible de l’indiquer explicitement :
// Variable
var nombre = 10 // Inférence : Swift déduit que 'nombre' est un Int
var autreNombre: Int // Annotation explicite
autreNombre = 20
// Constante
let constante = 30 // Inférence : Swift déduit que 'constante' est un Int
let autreConstante: Int = 40 // Annotation explicite
autreConstante = 50 // Erreur : impossible de modifier une constante
Vous pouvez déclarer plusieurs constantes ou variables sur une seule ligne, en les séparant par des virgules
var x = 0.0, y = 0.0, z = 0.0
let x = 0.0, y = 0.0, z = 0.0
Les noms de variables et de constantes peuvent contenir presque tous les caractères, y compris les caractères Unicode :
let π = 3.14159
let 你好 = "你好世界"
let 🐶🐮 = "dogcow"
let bébé = "👶🏽"
L'interpolation permet d'insérer des variables ou des constantes dans une chaîne de caractères :
let prenom = "Mathieu"
let age = 20
var message = "Bonjour, je m'appelle \(prenom) et j'ai \(age) ans."
print(message) // Affiche : Bonjour, je m'appelle Mathieu et j'ai 20 ans.
Swift propose plusieurs types de données :
var numero: Int // Nombres entiers, positifs ou négatifs
var uNumero: UInt // Nombres entiers, positifs uniquement
var booleen: Bool // True ou false
var chaine: String // Texte
var double: Double // Nombres décimaux avec une précision double
var flottant: Float // Nombres décimaux avec une précision simple
Swift supporte des structures conditionnelles comme if, else if, else, switch, et l'opérateur ternaire :
var x = 7
// Condition avec if
if x > 5 {
print("x est supérieur à 5")
}
// Condition avec if et else
if x > 10 {
print("x est supérieur à 10")
} else {
print("x est inférieur ou égal à 10")
}
// Condition avec if, else if et else
if x == 0 {
print("x est nul")
} else if x < 0 {
print("x est négatif")
} else {
print("x est positif")
}
//
// Opérateur ternaire
var message = x > 0 ? "Positif" : "Négatif"
// Switch case
switch x {
case 1, 2, 3:
print("Petit nombre")
case 7:
print("Nombre premier")
default:
print("Autre")
}
Swift propose plusieurs types de boucles :
// Boucle for
for i in 0...5 {
print(i) // Affiche les nombres de 0 à 5
}
for i in 0..<5 {
print(i) // Affiche les nombres de 0 à 4
}
// le underscore indique au compilateur de ne pas se preoccuper de l'affectation
for _ in 0..<5 {
print("Hello") // Affiche "Hello" 5 fois
}
// Boucle while
var i = 0
while i < 5 {
print(i)
i += 1
}
// Boucle repeat-while (do-while)
var j = 0
repeat {
print(j)
j += 1
} while j < 5
Une fonction sans paramètre est une fonction qui ne prend rien en entrée pour effectuer son travail. Elle exécute toujours la même action, sans avoir besoin d’informations supplémentaires.
func direBonjour() {
print("Bonjour !")
}
direBonjour() // Affiche : Bonjour !
Une fonction avec paramètres est une fonction qui prend des informations en entrée pour effectuer son travail. Ces informations, qu’on appelle des paramètres, permettent à la fonction de s’adapter et de produire un résultat différent selon ce qu’on lui donne.
func direBonjour(prenom: String) {
print("Bonjour, \(prenom) !")
}
direBonjour(prenom: "Mathieu") // Affiche : Bonjour, Mathieu !
Une fonction avec valeur de retour est une fonction qui, après avoir exécuté son travail, renvoie un résultat que l’on peut utiliser ailleurs dans le programme. Ce résultat est appelé la valeur de retour.
func additionner(a: Int, b: Int) -> Int {
return a + b
}
let resultat = additionner(a: 5, b: 3)
print(resultat) // Affiche : 8
Une fonction avec paramètre variadique est une fonction qui peut accepter un nombre illimité de valeurs pour un paramètre donné. Cela signifie qu’on peut passer autant d’arguments qu’on le souhaite pour ce paramètre, sans devoir en fixer un nombre exact à l’avance.
func moyenne(_ nombres: Double...) -> Double {
var total = 0.0
for nombre in nombres {
total += nombre
}
return total / Double(nombres.count)
}
let moy = moyenne(1, 2, 3, 4, 5)
print(moy) // Affiche : 3.0
Une fonction avec un paramètre par défaut est une fonction où certains paramètres ont une valeur déjà définie si l’utilisateur n’en fournit pas lorsqu’il appelle la fonction. Ces valeurs par défaut sont utilisées automatiquement.
func direBonjour(prenom: String = "Inconnu") {
print("Bonjour, \(prenom) !")
}
direBonjour() // Affiche : Bonjour, Inconnu !
direBonjour(prenom: "Mathieu") // Affiche : Bonjour, Mathieu !
Une fonction avec paramètres inout est une fonction qui peut modifier directement la valeur d’une variable passée en argument. Cela fonctionne en permettant à la fonction d’accéder à l’intérieur de la variable au lieu d’utiliser une copie de sa valeur.
func doubler(_ nombre: inout Int) {
nombre *= 2
}
var x = 10
doubler(&x)
print(x) // Affiche : 20
Une fonction avec valeur de retour optionnelle est une fonction qui peut soit :
Cela permet de gérer des cas où une fonction peut échouer ou ne pas avoir de réponse valable.
func diviser(_ a: Double, par b: Double) -> Double? {
if b == 0 {
return nil
}
return a / b
}
if let resultat = diviser(10, par: 2) {
print(resultat) // Affiche : 5.0
} else {
print("Division par zéro !")
}
Les étiquettes d'argument permettent de nommer les paramètres d'une fonction de manière plus explicite lors de son appel. Elles rendent le code plus lisible et plus compréhensible.
func direBonjour(a prenom: String) {
print("Bonjour, \(prenom) !")
}
direBonjour(a: "Mathieu") // Affiche : Bonjour, Mathieu !
Il est possible d'omettre les étiquettes d'argument pour rendre le code plus concis. Cela est utile lorsque le nom du paramètre est déjà explicite.
func direBonjour(_ prenom: String) {
print("Bonjour, \(prenom) !")
}
direBonjour("Mathieu") // Affiche : Bonjour, Mathieu !
Il est possible de définir des étiquettes d'argument pour les paramètres suivants, afin de rendre le code plus lisible et plus compréhensible.
func additionner(_ a: Int, et b: Int) -> Int {
return a + b
}
let somme = additionner(5, et: 3)
print(somme) // Affiche : 8
Il est possible de définir des étiquettes d'argument pour les paramètres précédents, afin de rendre le code plus lisible et plus compréhensible.
func additionner(a: Int, _ b: Int) -> Int {
return a + b
}
let total = additionner(a: 5, 3)
print(total) // Affiche : 8
Les structures de données en Swift sont des outils essentiels pour organiser, stocker et manipuler des informations dans un programme. Swift propose plusieurs structures intégrées, puissantes et flexibles, qui couvrent la majorité des besoins de développement.
Un tableau est une liste ordonnée d’éléments de même type. Il permet de stocker plusieurs valeurs dans une seule variable.
var fruits: [String] = ["Pomme", "Banane", "Orange"]
fruits.append("Mangue") // Ajouter un élément
fruits.remove(at: 1) // Supprimer l'élément à l'index 1
print(fruits) // Affiche : ["Pomme", "Orange", "Mangue"]
print(fruits[1]) // Affiche : Orange
Un dictionnaire est une collection non ordonnée de paires clé-valeur. Chaque clé est unique et associée à une valeur.
var capitales: [String: String] = ["France": "Paris", "Italie": "Rome"]
capitales["Espagne"] = "Madrid" // Ajouter une clé et une valeur
capitales["Italie"] = "Venise" // Modifier une valeur
capitales.removeValue(forKey: "France") // Supprimer une clé
print(capitales) // Affiche : ["Italie": "Venise", "Espagne": "Madrid"]
print(capitales["Espagne"]) // Affiche : Optional("Madrid")
print(capitales["Espagne"]!) // Affiche : Madrid
Un ensemble est une collection non ordonnée d’éléments uniques.
var couleurs: Set< String > = ["Rouge", "Vert", "Bleu"]
couleurs.insert("Jaune") // Ajouter un élément
couleurs.remove("Vert") // Supprimer un élément
print(couleurs) // Affiche : ["Rouge", "Bleu", "Jaune"]
let a: Set = [1, 2, 3]
let b: Set = [3, 4, 5]
print(a.union(b)) // [1, 2, 3, 4, 5] (union)
print(a.intersection(b)) // [3] (intersection)
print(a.subtracting(b)) // [1, 2] (soustraction)
Un tuple regroupe plusieurs valeurs dans une seule entité. Contrairement aux tableaux, les éléments d’un tuple peuvent être de types différents.
let personne = ("Alice", 25, true)
print(personne.0) // Affiche : Alice
print(personne.1) // Affiche : 25
print(personne.2) // Affiche : true
// Modifier une valeur
personne.1 = 40
print(personne.1) // Affiche : 40
let personne = (nom: "Alice", age: 25, estEtudiante: true)
print(personne.nom) // Affiche : Alice
Les structures (struct) sont l’un des types fondamentaux en Swift. Elles permettent de définir des types personnalisés qui peuvent contenir des propriétés (variables et constantes) et des méthodes (fonctions). Les struct sont largement utilisées pour organiser des données et ajouter des fonctionnalités dans un programme Swift.
struct Point {
var x: Double
var y: Double
// Méthode pour déplacer le point
mutating func move(dx: Double, dy: Double) {
x += dx
y += dy
}
}
// Création d'une instance
var point = Point(x: 3.0, y: 4.0)
// Affichage des coordonnées
print("Point initial : (\(point.x), \(point.y))")
// Déplacement du point
point.move(dx: 2.0, dy: -1.0)
print("Point après déplacement : (\(point.x), \(point.y))")
Exemple de struct avec initialisateur personnalisé
struct Rectangle {
var width: Double
var height: Double
// Initialiseur personnalisé
init(width: Double, height: Double) {
self.width = width
self.height = height
}
// Calcul de l'aire (propriété calculée)
var area: Double {
return width * height
}
}
let rectangle = Rectangle(width: 5.0, height: 10.0)
print("Aire du rectangle : \(rectangle.area)")
Immutabilité et propriétés mutables
Une instance d’une structure définie comme let est immutable. Les propriétés ne peuvent pas être modifiées.
let immutablePoint = Point(x: 1.0, y: 2.0)
immutablePoint.x = 5.0 // Erreur : Impossible de modifier une propriété d'une instance constante
Structures imbriquées
Une structure peut contenir d’autres structures. Par exemple, un rectangle peut être défini à partir de deux points.
struct Point {
var x: Double
var y: Double
}
struct Rectangle {
var topLeft: Point
var bottomRight: Point
var area: Double {
let width = bottomRight.x - topLeft.x
let height = bottomRight.y - topLeft.y
return width * height
}
}
let rect = Rectangle(topLeft: Point(x: 0, y: 10), bottomRight: Point(x: 5, y: 0))
print("Aire du rectangle : \(rect.area)")
Les classes sont des types de données de base en Swift, qui permettent de créer des objets avec des propriétés et des méthodes. Les classes sont des types référence, ce qui signifie que lorsqu’on les assigne à une variable ou qu’on les passe à une fonction, elles sont partagées plutôt que copiées.
class Personne {
var prenom: String
var age: Int
init(prenom: String, age: Int) {
self.prenom = prenom
self.age = age
}
func direBonjour() {
print("Bonjour, je m'appelle \(prenom) et j'ai \(age) ans.")
}
}
let personne = Personne(prenom: "Mathieu", age: 20)
personne.direBonjour() // Affiche : Bonjour, je m'appelle Mathieu et j'ai 20 ans.
personne.age = 27
personne.direBonjour() // Affiche : Bonjour, je m'appelle Mathieu et j'ai 27 ans.
Une classe peut hériter d’une autre classe pour partager et étendre ses fonctionnalités.
class Animal {
var name: String
init(name: String) {
self.name = name
}
func makeSound() {
print("\(name) fait un bruit.")
}
}
// Classe dérivée
class Dog: Animal {
func bark() {
print("\(name) aboie.")
}
// Redéfinition d'une méthode
override func makeSound() {
print("\(name) fait : Woof!")
}
}
let dog = Dog(name: "Rex")
dog.makeSound()
dog.bark()
Un déinitialiseur (deinit) est une méthode spéciale utilisée dans les classes pour exécuter du code juste avant que l’instance de la classe ne soit détruite. Cela permet de libérer des ressources, fermer des connexions ou effectuer un nettoyage nécessaire.
deinit {
// Code de nettoyage
}
Exemple : gestion de ressources
class FileHandler {
var fileName: String
init(fileName: String) {
self.fileName = fileName
print("Fichier \(fileName) ouvert.")
}
deinit {
print("Fichier \(fileName) fermé.")
}
}
// Bloc pour limiter la portée
do {
let handler = FileHandler(fileName: "document.txt")
// À la fin du bloc, handler est libéré et le déinitialiseur est appelé
}
Le déinitialiseur est utile pour gérer la mémoire et nettoyer les ressources associées à une instance lorsqu’elle est détruite. Swift s’en charge automatiquement via l’ARC, mais le déinitialiseur permet d’ajouter un traitement spécifique si nécessaire.
Les optionnels sont une fonctionnalité clé de Swift qui permet de gérer les valeurs manquantes ou inexistantes. Ils sont utilisés pour indiquer qu’une variable ou une constante peut soit contenir une valeur, soit être nulle (nil). Cela offre une manière sûre et explicite de travailler avec des données qui peuvent être absentes, tout en évitant les erreurs courantes liées à des pointeurs nuls.
Un optionnel est déclaré en ajoutant un point d’interrogation (?) après le type de la variable.
var name: String? // Peut contenir une valeur de type String ou être nil
name = "Alice" // Contient une valeur
name = nil // Maintenant, aucune valeur n'est présente
Pour utiliser la valeur d’un optionnel, il faut d’abord la “déballer” (unwrap). Il existe plusieurs façons de le faire.
Déballage forcé (!)Utilisé lorsque vous êtes certain que l’optionnel contient une valeur. Cependant, si l’optionnel est nil, cela provoque une erreur à l’exécution.
var name: String? = "Alice"
print(name!) // Affiche "Alice"
⚠️ Attention : Évitez d’utiliser le déballage forcé à moins d’être sûr à 100% que l’optionnel n’est pas nil.
Déballage conditionnel (if let)Permet de vérifier si une valeur est présente et de la déballer de manière sécurisée.
var name: String? = "Alice"
if let unwrappedName = name {
print("Bonjour, \(unwrappedName)!")
} else {
print("Aucun nom fourni.")
}
Déballage avec guard let
Utilisé pour forcer une valeur non-nil dans une fonction ou un bloc de code et quitter si la condition échoue.
func greetUser(name: String?) {
guard let unwrappedName = name else {
print("Nom manquant.")
return
}
print("Bonjour, \(unwrappedName)!")
}
Opérateur de coalescence (??)
Permet de fournir une valeur par défaut si l’optionnel est nil.
let username: String? = nil
let displayName = username ?? "Utilisateur inconnu"
print(displayName) // Affiche "Utilisateur inconnu"
Optionnels implicites
Si une valeur optionnelle est garantie d’avoir une valeur après son initialisation, on peut utiliser un optionnel implicite en ajoutant un point d’exclamation (!) après le type.
var email: String! = "test@example.com"
print(email) // Pas besoin de déballage explicite
⚠️ Attention : Cependant, l’utilisation des optionnels implicites doit être limitée, car elle comporte les mêmes risques que le déballage forcé.
En Swift, un protocole est un modèle (ou contrat) qui définit un ensemble de propriétés, méthodes, ou autres exigences qu’une classe, une structure, ou une énumération doit implémenter. Les protocoles permettent d’organiser le code, de garantir un comportement uniforme entre les types, et de faciliter l’utilisation du polymorphisme.
Un protocole est déclaré à l’aide du mot-clé protocol, suivi de son nom et de ses exigences.
protocol Vehicule {
var nombreDeRoues: Int { get }
func demarrer()
}
Une classe, une structure ou une énumération peut adopter un protocole en implémentant ses exigences.
struct Voiture: Vehicule {
var nombreDeRoues: Int = 4
func demarrer() {
print("La voiture démarre !")
}
}
let maVoiture = Voiture()
maVoiture.demarrer() // Affiche : La voiture démarre !
Si une propriété doit être modifiable par une classe ou une structure adoptant le protocole, ajoute { get set }.
protocol Personne {
var nom: String { get set }
func sePresenter()
}
struct Etudiant: Personne {
var nom: String
func sePresenter() {
print("Bonjour, je m'appelle \(nom) !")
}
}
var etudiant = Etudiant(nom: "Alice")
etudiant.sePresenter() // Affiche : Bonjour, je m'appelle Alice !
Un protocole peut être utilisé comme type pour une variable, une constante ou un paramètre.
func afficherDetails(vehicule: Vehicule) {
print("Nombre de roues : \(vehicule.nombreDeRoues)")
vehicule.demarrer()
}
let voiture = Voiture()
afficherDetails(vehicule: voiture)
// Affiche :
// Nombre de roues : 4
// La voiture démarre !
Un protocole peut hériter d’un ou plusieurs autres protocoles
protocol VehiculeMotorise: Vehicule {
var typeDeCarburant: String { get }
}
struct Moto: VehiculeMotorise {
var nombreDeRoues: Int = 2
var typeDeCarburant: String = "Essence"
func demarrer() {
print("La moto démarre !")
}
}
let moto = Moto()
print(moto.typeDeCarburant) // Affiche : Essence