Протоколы — это мощный инструмент языка программирования Swift, который позволяет разработчикам определять набор требований, которым должен соответствовать класс, структура или перечисление, чтобы считаться соответствующими конкретному протоколу. В этом руководстве мы рассмотрим, как протоколы работают в Swift и как их можно использовать для определения повторно используемого и модульного кода.

Во-первых, давайте определим простой протокол с именем Shape, который требует, чтобы соответствующие типы имели свойство area и метод perimeter.

protocol Shape {
    var area: Double { get }
    func perimeter() -> Double
}

Теперь давайте определим класс Circle, соответствующий протоколу Shape. Для этого нам просто нужно включить протокол Shape в объявление класса и реализовать требуемое свойство area и метод perimeter.

class Circle: Shape {
    let radius: Double
    var area: Double {
        return .pi * radius * radius
    }
    
    func perimeter() -> Double {
        return 2 * .pi * radius
    }
    
    init(radius: Double) {
        self.radius = radius
    }
}

Теперь любой экземпляр класса Circle будет считаться Shape, поскольку он соответствует протоколу Shape. Мы можем проверить это, создав экземпляр Circle и вызвав его методы area и perimeter.

let circle = Circle(radius: 5)
print(circle.area) // 78.53981633974483
print(circle.perimeter()) // 31.41592653589793
let circle = Circle(radius: 5)
print(circle.area) // 78.53981633974483
print(circle.perimeter()) // 31.41592653589793

Протоколы также могут иметь необязательные требования, то есть методы или свойства, которые не требуются для соответствия, но при желании могут быть реализованы с помощью соответствующих типов. Чтобы определить необязательное требование, нам просто нужно включить ключевое слово optional перед объявлением метода или свойства.

Давайте добавим необязательное свойство description в протокол Shape.

protocol Shape {
    var area: Double { get }
    func perimeter() -> Double
    var description: String { get }
}

Теперь давайте обновим класс Circle, чтобы реализовать необязательное свойство description.

class Circle: Shape {
    let radius: Double
    var area: Double {
        return .pi * radius * radius
    }
    
    func perimeter() -> Double {
        return 2 * .pi * radius
    }
    
    var description: String {
        return "Circle with radius: \(radius)"
    }
    
    init(radius: Double) {
        self.radius = radius
    }
}

Теперь мы можем вызвать свойство description в нашем экземпляре circle, чтобы увидеть реализацию необязательного требования.

let circle = Circle(radius: 5)
print(circle.description) // Circle with radius: 5

Протоколы также могут быть расширены для предоставления реализации по умолчанию для дополнительных требований или для добавления дополнительных функций к соответствующим типам. Давайте расширим протокол Shape, чтобы добавить реализацию по умолчанию для свойства description.

extension Shape {
    var description: String {
        return "Unidentified shape"
    }
}

Теперь, если класс не реализует свойство description, он будет автоматически использовать реализацию по умолчанию, предоставляемую расширением.

В заключение, протоколы — это полезный инструмент в Swift, который позволяет разработчикам определять набор требований, которым должен соответствовать класс, структура или перечисление, чтобы считаться соответствующими конкретному протоколу. Протоколы также могут иметь необязательные требования и могут быть расширены для обеспечения реализации по умолчанию или дополнительных функций для соответствующих типов. Протоколы позволяют создавать многоразовый и модульный код и могут быть важной частью любого проекта Swift.

Использованная литература: