Что такое extension? Что может быть в extension, а чего нет?ios-33

Что такое extension?

Extension (расширение) - это мощный механизм Swift, позволяющий добавлять новую функциональность к существующим типам, даже если у вас нет доступа к их исходному коду.

Основные характеристики:

  • Не изменяет оригинальный тип
  • Не поддерживает наследование
  • Может применяться к классам, структурам, перечислениям и протоколам

Что МОЖНО помещать в extension?

1. Вычисляемые свойства

extension Double {
    var km: Double { return self * 1_000.0 }
    var cm: Double { return self / 100.0 }
}

2. Методы

extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self { task() }
    }
}

3. Инициализаторы

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)
    }
}

4. Сабскрипты

extension Int {
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex { decimalBase *= 10 }
        return (self / decimalBase) % 10
    }
}

5. Вложенные типы

extension Int {
    enum Kind { case negative, zero, positive }
    var kind: Kind {
        switch self {
        case 0: return .zero
        case let x where x > 0: return .positive
        default: return .negative
        }
    }
}

6. Реализация протоколов

extension MyType: SomeProtocol {
    // реализация требований протокола
}

Что НЕЛЬЗЯ помещать в extension?

1. Хранимые свойства

extension UIView {
    var tagString: String = "" // Ошибка: Extensions cannot contain stored properties
}

Решение: Использовать ассоциированные объекты или вычисляемые свойства

2. Деинициализаторы

extension UIViewController {
    deinit { print("Deinit") } // Ошибка
}

3. Наблюдатели свойств

extension UIView {
    var x: CGFloat {
        didSet { } // Ошибка
    }
}

4. Переопределение существующих методов

extension String {
    override func lowercased() -> String { // Ошибка
        return "custom implementation"
    }
}

Исключение: Можно переопределять методы в extension'ах внутри того же модуля (т.н. "@objc dynamic" методы)

Практические советы по использованию extensions

  1. Организация кода:

    // Разделяем функциональность по extensions
    class MyViewController: UIViewController {
        // основной код
    }
    
    extension MyViewController: UITableViewDataSource { ... }
    extension MyViewController: UITableViewDelegate { ... }
    
  2. Protocol-Oriented Programming:

    protocol Flyable { ... }
    extension Flyable {
        func fly() { print("Flying!") }
    }
    
  3. Default реализации:

    protocol Identifiable {
        var id: String { get }
    }
    
    extension Identifiable {
        var id: String { return UUID().uuidString }
    }
    

Резюмируем

Можно в extension:

  • Добавлять вычисляемые свойства
  • Добавлять методы (включая статические)
  • Реализовывать новые инициализаторы
  • Добавлять сабскрипты
  • Определять вложенные типы
  • Реализовывать протоколы

Нельзя в extension:

  • Добавлять хранимые свойства
  • Создавать деинициализаторы
  • Добавлять наблюдатели свойств
  • Переопределять существующие методы (с ограничениями)

Extensions - это мощный инструмент для организации кода и расширения функциональности без модификации исходных типов.