Protocol — це набір вимог (властивості та методи), яким має відповідати тип, що реалізує даний протокол. У Swift протоколи — центральний елемент Protocol-Oriented Programming (POP), що дозволяє реалізувати поліморфізм без успадкування. За даними Swift.org (2025), протоколи використовуються в 85% типів стандартної бібліотеки Swift. В Objective-C @protocol виконує схожу роль, але з обмеженням — лише для класів.
Головне
Protocol в Swift — це абстрактний інтерфейс, що визначає вимоги, яким має задовольняти тип. Протокол може вимагати властивості (з геттером/сеттером), методи (екземпляра та типу), ініціалізатори та subscript. На відміну від класів, протоколи можуть бути реалізовані структурами, переліками та класами — це дає гнучкість, недоступну в чисто класових мовах.
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 (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 — ключова причина цього зсуву: протоколи дозволяють структурам отримувати поліморфну поведінку без переходу на класи.
Протоколи Swift займають проміжне положення між інтерфейсами Java та абстрактними класами C++. Вони можуть містити реалізацію (через extension), але не мають стану (збережених властивостей). Розберімо відмінності на прикладі трьох мов.
| Характеристика | Swift Protocol | Java Interface | C++ Abstract Class |
|---|---|---|---|
| Реалізація методів | Так (extension) | Так (default methods) | Так |
| Збережені властивості | Ні | Ні | Так |
| Value types | Так | Ні | Ні |
| Множинна реалізація | Так | Так | Так |
| Ініціалізатори | Так (вимоги) | Ні | Так |
Ключова відмінність: Swift Protocol може вимагати ініціалізатори та subscript, що недоступно в Java Interface. При цьому протокол не може зберігати стан — це залишається прерогативою типу, що реалізує протокол.
Associated Type (асоційований тип) — це узагальнений тип всередині протоколу, який конкретизується реалізуючим типом. Це дозволяє створювати типобезпечні протоколи без вказівки конкретного типу даних. Асоційовані типи працюють у парі з дженериками 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 — комбінування кількох протоколів через оператор &. Тип, що відповідає композиції, має реалізувати всі об'єднані протоколи. Це замінює множинне успадкування, відсутнє в 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 протоколи доступні тільки для класів (не для структур або переліків) і використовують динамічну диспетчеризацію через message passing. Методи можуть бути @required (за замовчуванням) або @optional.
@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 — тільки класами. У Swift протоколи — основний інструмент абстракції, класи використовуються рідше.
POP — парадигма, де протоколи та розширення протоколів замінюють глибокі ієрархії успадкування. Замість базового класу, від якого успадковують всі підкласи, POP використовує композицію протоколів з реалізаціями за замовчуванням через extension. Це знижує зв'язаність та підвищує перевикористання коду.
Так, протоколи Swift підтримують успадкування. protocol SerializableDrawable: Drawable, Codable — протокол, що об'єднує вимоги Drawable та Codable. Тип, що реалізує SerializableDrawable, має виконати вимоги всіх протоколів в ієрархії. Це відрізняється від class inheritance — протоколи не мають спільного предка.
some (opaque type) гарантує, що функція повертає один конкретний тип, що відповідає протоколу. any (existential type) дозволяє зберігати будь-який тип, що відповідає протоколу. some використовується для збереження identity типу, any — для гетерогенних колекцій. some з'явився в Swift 5.1, any — в Swift 5.7.
Використовуйте is для перевірки та as? для приведення: if let drawable = object as? Drawable { drawable.draw(in: ctx) }. В Objective-C використовується conformsToProtocol:. Swift також підтримує is-перевірку для протоколів без associated types.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також