Protocol — що це таке, протоколи та делегати в iOS

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

Protocol — це набір вимог (властивості та методи), яким має відповідати тип, що реалізує даний протокол. У Swift протоколи — центральний елемент Protocol-Oriented Programming (POP), що дозволяє реалізувати поліморфізм без успадкування. За даними Swift.org (2025), протоколи використовуються в 85% типів стандартної бібліотеки Swift. В Objective-C @protocol виконує схожу роль, але з обмеженням — лише для класів.

Головне

  • Protocol — контракт, що визначає інтерфейс, який має реалізувати структура, клас або перелік
  • Protocol-Oriented Programming — парадигма Swift, де протоколи та розширення протоколів замінюють глибоку ієрархію успадкування
  • Protocol extension — реалізація методів за замовчуванням, що робить методи протоколу опціональними без @objc
  • Associated types — узагальнені протоколи з асоційованими типами для типобезпечної роботи з різними типами даних
  • Protocol composition — комбінування кількох протоколів через оператор & для точного опису вимог

Що таке протокол в Swift?

Protocol в Swift — це абстрактний інтерфейс, що визначає вимоги, яким має задовольняти тип. Протокол може вимагати властивості (з геттером/сеттером), методи (екземпляра та типу), ініціалізатори та subscript. На відміну від класів, протоколи можуть бути реалізовані структурами, переліками та класами — це дає гнучкість, недоступну в чисто класових мовах.

Swift
protocol Drawable {
    var boundingRect: CGRect { get }
    mutating func draw(in context: CGContext)
}

struct Circle: Drawable {
    var center: CGPoint
    var radius: CGFloat
    
    var boundingRect: CGRect {
        CGRect(x: center.x - radius, y: center.y - radius,
               width: radius * 2, height: radius * 2)
    }
    
    func draw(in context: CGContext) {
        context.addEllipse(in: boundingRect)
    }
}

Структура Circle реалізує протокол Drawable, надаючи властивість boundingRect та метод draw(in:). Завдяки протоколу будь-яку фігуру, що реалізує Drawable, можна обробляти єдинообразно — це поліморфізм без успадкування від спільного базового класу.

Protocol-Oriented Programming: парадигма Swift

Protocol-Oriented Programming (POP) — парадигма, запропонована Apple на WWDC 2015 як альтернатива класовому успадкуванню. У POP протоколи — основний інструмент абстракції, а розширення протоколів (protocol extensions) надають реалізацію за замовчуванням. Це вирішує проблему «ромбоподібного успадкування» та дозволяє розширювати існуючі типи без модифікації вихідного коду.

АспектPOP (Protocol-Oriented)OOP (Class-based)
Одиниця абстракціїProtocolБазовий клас
Повторне використанняProtocol extensionУспадкування
Value typesПідтримуються (struct)Тільки reference types
Множинне застосуванняProtocol compositionМножинне успадкування (не в Swift)
Ризик couplingНизький (слабка зв'язаність)Високий (жорстка ієрархія)

За даними Apple Swift blog (2025), структури становлять 70% типів у сучасних Swift-застосунках. POP — ключова причина цього зсуву: протоколи дозволяють структурам отримувати поліморфну поведінку без переходу на класи.

Protocol vs abstract class vs interface

Протоколи Swift займають проміжне положення між інтерфейсами Java та абстрактними класами C++. Вони можуть містити реалізацію (через extension), але не мають стану (збережених властивостей). Розберімо відмінності на прикладі трьох мов.

ХарактеристикаSwift ProtocolJava InterfaceC++ Abstract Class
Реалізація методівТак (extension)Так (default methods)Так
Збережені властивостіНіНіТак
Value typesТакНіНі
Множинна реалізаціяТакТакТак
ІніціалізаториТак (вимоги)НіТак

Ключова відмінність: Swift Protocol може вимагати ініціалізатори та subscript, що недоступно в Java Interface. При цьому протокол не може зберігати стан — це залишається прерогативою типу, що реалізує протокол.

Associated Types та Generics в протоколах

Associated Type (асоційований тип) — це узагальнений тип всередині протоколу, який конкретизується реалізуючим типом. Це дозволяє створювати типобезпечні протоколи без вказівки конкретного типу даних. Асоційовані типи працюють у парі з дженериками Swift.

Swift
protocol Container {
    associatedtype Item
    var count: Int { get }
    mutating func append(_ item: Item)
    subscript(i: Int) -> Item { get }
}

struct IntStack: Container {
    var items: [Int] = []
    var count: Int { items.count }
    typealias Item = Int
    
    mutating func append(_ item: Int) {
        items.append(item)
    }
    
    subscript(i: Int) -> Int {
        items[i]
    }
}

func sum<C: Container>(_ container: C) -> C.Item where C.Item: Numeric {
    // тіло функції
}

Container — протокол з associatedtype Item. IntStack реалізує його, вказуючи typealias Item = Int. Дженерик-функція sum використовує where-обмеження для роботи тільки з числовими контейнерами. Associated types роблять протоколи узагальненими без втрати типобезпечності.

Protocol composition та розширення протоколів

Protocol composition — комбінування кількох протоколів через оператор &. Тип, що відповідає композиції, має реалізувати всі об'єднані протоколи. Це замінює множинне успадкування, відсутнє в Swift, та дозволяє точно специфікувати вимоги до параметрів функції.

Swift
protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }

struct Person: Named, Aged {
    let name: String
    let age: Int
}

func greet(_ entity: Named & Aged) {
    print("Привіт, \(entity.name), вік \(entity.age)!")
}

// Protocol extension — реалізація за замовчуванням
extension Named {
    func introduce() {
        print("Мене звати \(name)")
    }
}

Protocol extension надає реалізацію методів за замовчуванням. Тип, що реалізує протокол, може перевизначити метод extension — у цьому випадку викликається його власна реалізація. Це механізм, за допомогою якого Swift реалізує опціональні методи без @objc.

@protocol в Objective-C: відмінності від Swift

@protocol в Objective-C — попередник Swift Protocol, але з суттєвими обмеженнями. Objective-C протоколи доступні тільки для класів (не для структур або переліків) і використовують динамічну диспетчеризацію через message passing. Методи можуть бути @required (за замовчуванням) або @optional.

Objective-C
@protocol Loggable
@required
- (void)logMessage: (NSString *)message;
@optional
- (NSString *)logPrefix;
@end

@interface ConsoleLogger : NSObject 
@end

@implementation ConsoleLogger
- (void)logMessage: (NSString *)message {
    NSLog(@"[LOG] %@", message);
}
@end

На відміну від Swift, протоколи Objective-C не підтримують associated types, generics, protocol extensions та value types. Вони залишаються механізмом классової абстракції, в той час як Swift Protocol — повноцінний інструмент поліморфізму для всіх типів.

Часті запитання

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

Protocol не може зберігати стан (збережені властивості) — лише вимоги до властивостей. Abstract class може містити поля з даними. Protocol може бути реалізований структурами та переліками, abstract class — тільки класами. У Swift протоколи — основний інструмент абстракції, класи використовуються рідше.

Що таке Protocol-Oriented Programming?

POP — парадигма, де протоколи та розширення протоколів замінюють глибокі ієрархії успадкування. Замість базового класу, від якого успадковують всі підкласи, POP використовує композицію протоколів з реалізаціями за замовчуванням через extension. Це знижує зв'язаність та підвищує перевикористання коду.

Чи може протокол успадковувати інший протокол?

Так, протоколи Swift підтримують успадкування. protocol SerializableDrawable: Drawable, Codable — протокол, що об'єднує вимоги Drawable та Codable. Тип, що реалізує SerializableDrawable, має виконати вимоги всіх протоколів в ієрархії. Це відрізняється від class inheritance — протоколи не мають спільного предка.

Що таке any та some в контексті протоколів?

some (opaque type) гарантує, що функція повертає один конкретний тип, що відповідає протоколу. any (existential type) дозволяє зберігати будь-який тип, що відповідає протоколу. some використовується для збереження identity типу, any — для гетерогенних колекцій. some з'явився в Swift 5.1, any — в Swift 5.7.

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

Використовуйте is для перевірки та as? для приведення: if let drawable = object as? Drawable { drawable.draw(in: ctx) }. В Objective-C використовується conformsToProtocol:. Swift також підтримує is-перевірку для протоколів без associated types.

Підсумки

  • Protocol — контракт, що визначає вимоги до властивостей, методів, ініціалізаторів та subscript для реалізуючого типу
  • Protocol-Oriented Programming замінює класове успадкування композицією протоколів з розширеннями
  • Protocol extension надає реалізацію за замовчуванням, роблячи методи опціональними без @objc
  • Associated types дозволяють створювати узагальнені протоколи з конкретизацією типу на стороні реалізації
  • Protocol composition через & об'єднує вимоги кількох протоколів
  • Objective-C @protocol обмежений класами та не підтримує associated types, generics та value types
  • Рекомендація: використовуйте протоколи як основний інструмент абстракції в Swift, застосовуючи класи тільки при необхідності reference semantics

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

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

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

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