Protocol у Swift — що це, синтаксис і можливості

Автор: IT Sectr Опубліковано: 2026-06-17 Час читання: 6 хв

Protocol у Swift — це контракт, що визначає набір вимог, яким повинен задовольняти будь-який тип, що його прийняв. Протоколи лежать в основі протокол-орієнтованого програмування (POP) — парадигми, рекомендованої Apple для Swift поряд з класичним ООП. За даними Apple Documentation, 2026, структури, класи та enum можуть приймати протоколи, що робить архітектуру гнучкою та тестованою.

Головне

  • Protocol — контракт із вимогами для структур, класів та enum
  • Вимоги включають методи, властивості, ініціалізатори та subscripts
  • Protocol Composition дозволяє комбінувати кілька протоколів
  • POP — протокол-орієнтоване програмування, альтернатива успадкуванню
  • Protocol Extensions додають реалізації за замовчуванням для методів

Що таке Protocol у Swift?

Protocol — це абстрактний інтерфейс, що визначає, що повинен уміти тип, але не як він це робить. У Swift протокол — аналог інтерфейсів з Java або Go, але з додатковими можливостями.

Протокол може вимагати:

  • Методи екземпляра та типу (статичні)
  • Властивості із зазначенням { get } або { get set }
  • Ініціалізатори
  • Subscripts
  • Асоційовані типи (дженерики на рівні протоколу)

За даними WWDC 2015, Apple представила Protocol-Oriented Programming як фундаментальний підхід до архітектури Swift-додатків. На відміну від ООП, де успадкування класів створює жорсткі ієрархії, POP пропонує композицію протоколів. Це дає гнучкість: один тип може відповідати кільком протоколам, отримуючи їхні вимоги та реалізації через extensions.

Синтаксис оголошення протоколів

Protocol оголошується ключовим словом protocol з іменем і тілом.

swift
protocol Drawable {
    func draw(context: CGContext)
    var boundingBox: CGRect { get }
}

Тип приймає протокол через двокрапку після імені:

swift
struct Circle: Drawable {
    let center: CGPoint
    let radius: CGFloat

    func draw(context: CGContext) {
        context.addArc(center: center, radius: radius, ...)
    }

    var boundingBox: CGRect {
        CGRect(x: center.x - radius, y: center.y - radius,
               width: radius * 2, height: radius * 2)
    }
}

Один тип може прийняти кілька протоколів через кому: struct MyType: ProtocolA, ProtocolB. Компілятор перевіряє, що всі вимоги кожного протоколу виконані.

Вимоги методів і властивостей

Вимоги властивостей вказуються з ключовим словом var і специфікаторами доступу { get } або { get set }.

swift
protocol UserProtocol {
    var name: String { get }
    var age: Int { get set }
    static var maxAge: Int { get }
    mutating func updateName(_ newName: String)
}

Ключове слово mutating у протоколі означає, що метод може змінювати self. Структури повинні реалізувати такий метод як mutating, класи — можуть опустити. Вимоги методів вказуються з повною сигнатурою, включаючи мітки параметрів.

Успадкування протоколів

Protocol може успадковувати інший протокол, додаючи нові вимоги. Це створює ієрархію контрактів без жорсткої прив’язки до класів.

swift
protocol Vehicle {
    var speed: Double { get set }
    func move()
}

protocol Flyable: Vehicle {
    var altitude: Double { get set }
    func takeOff()
}

Тип, що приймає Flyable, повинен виконати вимоги обох протоколів — і Vehicle, і Flyable. Swift підтримує множинне успадкування протоколів: protocol A: B, C.

Protocol Composition

Protocol Composition — механізм, що дозволяє вказати, що тип повинен відповідати кільком протоколам одночасно, без створення нового протоколу-комбінації.

swift
func render(_ item: Drawable & Animatable) {
    item.draw(context: ...)
    item.animate(duration: 0.3)
}

Composition (&) працює в параметрах функцій, змінних і generic-обмеженнях. Компілятор перевіряє, що переданий тип одночасно задовольняє всі протоколи. Composition часто використовується в SwiftUI: some View — це generic із composition.

Protocol Composition є кращим за створення ієрархії успадкування: замість protocol A: B, C можна прийняти B & C безпосередньо. Це дає гнучкість і знижує зв’язаність. Composition особливо зручний у параметрах функцій і generic-обмеженнях, де потрібно тимчасово об’єднати вимоги без створення проміжного протоколу. Це знижує кількість допоміжних типів у коді.

Protocol як тип

Protocol може використовуватися як тип змінної, параметра функції або елемента колекції. Це називається existential type.

swift
var drawableItem: Drawable
let items: [Drawable] = [Circle(...), Rectangle(...)]

func process(drawables: [any Drawable]) {
    for item in drawables {
        item.draw(context: ...)
    }
}

Ключове слово any (Swift 5.6+) явно вказує на existential. Без any компілятор видає попередження. Swift також підтримує some (opaque types) для приховування конкретного типу за протоколом — це стандартний прийом у SwiftUI.

Типові помилки з протоколами

При роботі з протоколами розробники часто допускають кілька повторюваних помилок.

  • Забули про mutating — метод у протоколі позначений як mutating, а структура реалізує його без ключового слова
  • Protocol as type замість generic — використання Drawable замість <T: Drawable> там, де потрібен конкретний тип
  • Циклічне посилання протоколу — протокол, що посилається сам на себе через асоційований тип, без коректного вирішення
  • Class-only protocol — використання AnyObject без необхідності, що виключає struct та enum

Часто задавані питання

Чим protocol відрізняється від abstract class?

Protocol визначає тільки вимоги без реалізації (до protocol extensions). Abstract class може містити реалізацію та стан. У Swift немає abstract класів — їх роль виконують протоколи з extensions.

Чи може struct прийняти protocol?

Так, структури, класи та enum — усі можуть приймати протоколи. Це основа POP: ви не зобов’язані використовувати класи для організації архітектури. Структури з протоколами дають value semantics та імутабельність.

Що таке асоційований тип у протоколі?

Асоційований тип (associatedtype) — placeholder для типу, який реалізуючий тип визначає самостійно. Приклад: Collection має associatedtype Element. Це generic на рівні протоколу.

Чи можна обмежити протокол тільки для класів?

Так, додайте успадкування від AnyObject: protocol MyProtocol: AnyObject. Тоді тільки класи зможуть прийняти цей протокол. Це корисно для weak-посилань і делегатів.

Як перевірити відповідність протоколу в runtime?

Використовуйте is для перевірки та as? для приведення: if let drawable = item as? Drawable. Це працює тільки для протоколів без асоційованих типів.

Підсумки

  • Protocol — контракт для методів, властивостей, ініціалізаторів та subscripts
  • Class, struct, enum — усі типи можуть приймати протоколи
  • Успадкування протоколів створює ієрархію контрактів без жорсткої зв’язаності
  • Protocol Composition (&) комбінує протоколи без успадкування
  • Existential types (any) та opaque types (some) — два способи роботи з протоколами
  • POP рекомендовано Apple як альтернатива класичному успадкуванню класів
  • Protocol Extensions дозволяють додавати реалізації за замовчуванням

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також