Extensions en Swift

Rendez les types de la bibliothèque de Swift plus utiles en leur ajoutant vos propres méthodes.

Les extensions en Swift permettent d'ajouter de nouvelles fonctionnalités à des types existants, comme des classes, des structures, des énumérations, et même des protocoles, sans avoir besoin de modifier leur code source. Cela est particulièrement utile pour organiser le code, ajouter des fonctionnalités à des types tiers, ou ajouter des fonctionnalités de manière modulaire.

1. Définition d'une Extension

Les extensions sont définies avec le mot-clé extension, suivi du type que vous souhaitez étendre. Vous pouvez ajouter des propriétés calculées, des méthodes, des initialisateurs, des sous-scripts, des méthodes de classe, et des protocoles.

extension String {
    func isPalindrome() -> Bool {
        let reversed = String(self.reversed())
        return self == reversed
    }
}

let word = "radar"
print(word.isPalindrome())  // Affiche : true

2. Propriétés Calculées

Les extensions permettent d'ajouter des propriétés calculées à un type existant. Notez que vous ne pouvez pas ajouter des propriétés stockées à un type via une extension.

extension Double {
    var squared: Double {
        return self * self
    }
}

let number = 3.0
print(number.squared)  // Affiche : 9.0

3. Méthodes d'Instance

Les extensions peuvent ajouter des méthodes d'instance qui peuvent être appelées sur des instances du type étendu.

extension Int {
    func isEven() -> Bool {
        return self % 2 == 0
    }
}

let number = 4
print(number.isEven())  // Affiche : true

4. Méthodes de Classe

Vous pouvez ajouter des méthodes de classe (statique) via les extensions, ce qui est utile pour fournir des fonctionnalités supplémentaires à la classe elle-même.

extension String {
    static func defaultGreeting() -> String {
        return "Hello, world!"
    }
}

print(String.defaultGreeting())  // Affiche : "Hello, world!"

5. Initialisateurs

Les extensions peuvent ajouter des initialisateurs aux types. Cependant, vous ne pouvez pas ajouter des initialisateurs désignés aux types via des extensions; vous pouvez seulement ajouter des initialisateurs de commodité.

extension CGRect {
    init(center: CGPoint, size: CGSize) {
        let origin = CGPoint(x: center.x - size.width / 2, y: center.y - size.height / 2)
        self.init(origin: origin, size: size)
    }
}

let center = CGPoint(x: 50, y: 50)
let size = CGSize(width: 100, height: 100)
let rect = CGRect(center: center, size: size)

6. Sous-Scripts

Les extensions peuvent ajouter des sous-scripts, permettant d’accéder aux membres d'un type de manière similaire aux indexeurs.

extension Array {
    subscript(safe index: Int) -> Element? {
        return index >= 0 && index < count ? self[index] : nil
    }
}

let numbers = [1, 2, 3, 4, 5]
print(numbers[safe: 2] ?? "Index hors limites")  // Affiche : 3
print(numbers[safe: 10] ?? "Index hors limites") // Affiche : "Index hors limites"

7. Conformité aux Protocoles

Les extensions peuvent être utilisées pour rendre un type conforme à un protocole. Cela permet de diviser l'implémentation du protocole en plusieurs extensions si nécessaire.

protocol Describable {
    func describe() -> String
}

extension Int: Describable {
    func describe() -> String {
        return "Le nombre est \(self)."
    }
}

let number = 42
print(number.describe())  // Affiche : "Le nombre est 42."

8. Extensions et Protocoles

Vous pouvez également ajouter des méthodes et des propriétés à des protocoles via des extensions. Cela permet de fournir des implémentations par défaut pour des méthodes ou des propriétés définies dans le protocole.

protocol Printable {
    func printDetails()
}

extension Printable {
    func printDetails() {
        print("Détails imprimés.")
    }
}

struct Document: Printable {}

let doc = Document()
doc.printDetails()  // Affiche : "Détails imprimés."

9. Extensions et Classes

Les extensions peuvent également être utilisées pour ajouter des fonctionnalités à des classes sans avoir à modifier la définition de la classe. Ceci est particulièrement utile pour ajouter des fonctionnalités aux classes fournies par des frameworks tiers.

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

extension Person {
    func greet() {
        print("Bonjour, je suis \(name).")
    }
}

let person = Person(name: "Alice")
person.greet()  // Affiche : "Bonjour, je suis Alice."

10. Limites des Extensions

  • Pas de Propriétés Stockées : Vous ne pouvez pas ajouter des propriétés stockées aux types via des extensions. Vous pouvez uniquement ajouter des propriétés calculées.
  • Pas d'Override : Les extensions ne permettent pas de remplacer ou de surcharger les méthodes existantes. Vous pouvez seulement ajouter de nouvelles méthodes.
  • Pas d'Initialisateurs Désignés : Vous ne pouvez pas ajouter des initialisateurs désignés via des extensions, mais vous pouvez ajouter des initialisateurs de commodité.