Les constructeurs

Apprenez à construire vos objets en leur donnant leurs valeurs initiales.

Les constructeurs, également appelés initialiseurs, sont des méthodes spéciales utilisées pour créer des instances d'une classe, d'une structure (struct), ou d'une énumération (enum). Les initialiseurs configurent les propriétés initiales de l'instance avant que celle-ci ne soit utilisée. Chaque type peut avoir plusieurs initialiseurs pour permettre différentes manières de créer une instance.

1. Initialiseur Simple

Un initialiseur simple est défini avec le mot-clé init. Il configure les propriétés de l'instance au moment de sa création.

struct Person {
    var name: String
    var age: Int
    // Initialiseur simple
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

let person = Person(name: "Alice", age: 30)
print("Nom : \(person.name), Âge : \(person.age)")  // Affiche : "Nom : Alice, Âge : 30"

2. Initialiseurs avec Paramètres Optionnels

Les initialiseurs peuvent accepter des paramètres optionnels pour créer une instance avec des propriétés qui ne sont pas toujours requises.

struct Person {
    var name: String
    var age: Int?
    // Initialiseur avec un paramètre optionnel
    init(name: String, age: Int? = nil) {
        self.name = name
        self.age = age
    }
}

let personWithAge = Person(name: "Bob", age: 25)
let personWithoutAge = Person(name: "Charlie")
print("Nom : \(personWithAge.name), Âge : \(personWithAge.age ?? 0)")  // Affiche : "Nom : Bob, Âge : 25"
print("Nom : \(personWithoutAge.name), Âge : \(personWithoutAge.age ?? 0)")  // Affiche : "Nom : Charlie, Âge : 0"

3. Initialiseurs avec Paramètres par Défaut

Les initialiseurs peuvent également avoir des paramètres avec des valeurs par défaut, simplifiant ainsi la création d'instances.

struct Car {
    var brand: String
    var year: Int
    // Initialiseur avec des paramètres par défaut
    init(brand: String = "Tesla", year: Int = 2024) {
        self.brand = brand
        self.year = year
    }
}

let defaultCar = Car()  // Utilise les valeurs par défaut
let customCar = Car(brand: "Ford", year: 2020)
print("Voiture par défaut : \(defaultCar.brand), \(defaultCar.year)")  // Affiche : "Voiture par défaut : Tesla, 2024"
print("Voiture personnalisée : \(customCar.brand), \(customCar.year)")  // Affiche : "Voiture personnalisée : Ford, 2020"

4. Initialiseurs Failsafe (Initializers with Failures)

Les initialiseurs en Swift peuvent échouer, c'est-à-dire qu'ils peuvent retourner nil s'ils ne parviennent pas à initialiser l'instance. Ces initialiseurs sont appelés failable initializers et sont définis avec init?.

struct Temperature {
    var celsius: Double
    // Initialiseur qui échoue si la température dépasse une certaine limite
    init?(celsius: Double) {
        if celsius < -273.15 {
            return nil  // Échec si la température est physiquement impossible
        }
        self.celsius = celsius
    }
}

if let validTemp = Temperature(celsius: -100) {
    print("Température valide : \(validTemp.celsius)°C")
} else {
    print("Température invalide")
}

if let invalidTemp = Temperature(celsius: -300) {
    print("Température valide : \(invalidTemp.celsius)°C")
} else {
    print("Température invalide")  // Affiche : "Température invalide"
}

5. Initialiseurs Désignés et de Commodité (Designated and Convenience Initializers)

a. Initialiseurs Désignés (Designated Initializers)

Un initialiseur désigné est l'initialiseur principal d'une classe ou d'une structure. Il initialise directement toutes les propriétés de la classe ou de la structure. Les classes doivent toujours avoir au moins un initialiseur désigné, sauf si elles héritent tous leurs initialiseurs d'une superclasse.

class Vehicle {
    var brand: String
    var year: Int
    // Initialiseur désigné
    init(brand: String, year: Int) {
        self.brand = brand
        self.year = year
    }
}

class Car: Vehicle {
    var isElectric: Bool
    // Initialiseur désigné
    init(brand: String, year: Int, isElectric: Bool) {
        self.isElectric = isElectric
        super.init(brand: brand, year: year)  // Appel à l'initialiseur de la superclasse
    }
}

b. Initialiseurs de Commodité (Convenience Initializers)

Les initialiseurs de commodité sont des initialiseurs supplémentaires qui permettent de simplifier la création d'une instance. Ils appellent un autre initialiseur désigné de la même classe pour réaliser une partie ou la totalité de l'initialisation.

class Car {
    var brand: String
    var year: Int
    var isElectric: Bool
    // Initialiseur désigné
    init(brand: String, year: Int, isElectric: Bool) {
        self.brand = brand
        self.year = year
        self.isElectric = isElectric
    }
    // Initialiseur de commodité
    convenience init(brand: String, isElectric: Bool) {
        self.init(brand: brand, year: 2024, isElectric: isElectric)
    }
}

let electricCar = Car(brand: "Tesla", isElectric: true)
print("Voiture : \(electricCar.brand), Année : \(electricCar.year), Électrique : \(electricCar.isElectric)")
// Affiche : "Voiture : Tesla, Année : 2024, Électrique : true"

6. Initialisation de Classes Héritées

Lorsqu'une classe hérite d'une autre, les initialiseurs de la classe parente doivent être appelés en premier dans le cadre de l'initialisation de la sous-classe. Cela garantit que toutes les propriétés héritées sont correctement configurées.

class Animal {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Dog: Animal {
    var breed: String
    init(name: String, breed: String) {
        self.breed = breed
        super.init(name: name)  // Appel à l'initialiseur de la superclasse
    }
}

let dog = Dog(name: "Buddy", breed: "Golden Retriever")
print("Nom : \(dog.name), Race : \(dog.breed)")  // Affiche : "Nom : Buddy, Race : Golden Retriever"

7. Initialiseurs Requis (Required Initializers)

Les initialiseurs requis sont des initialiseurs qui doivent être implémentés par toutes les sous-classes. Ils sont définis avec le mot-clé required.

class Animal {
    var name: String
    required init(name: String) {
        self.name = name
    }
}

class Dog: Animal {
    var breed: String
    required init(name: String, breed: String) {
        self.breed = breed
        super.init(name: name)
    }
}