Protocol — набор от изисквания (свойства и методи), на които типът, имплементиращ дадения протокол, трябва да отговаря. В Swift протоколите са централен елемент на Protocol-Oriented Programming (POP), позволяващ полиморфизъм без наследяване. Според Swift.org (2025), протоколите се използват в 85% от типовете на стандартната библиотека на Swift. В Objective-C @protocol играе подобна роля, но с ограничение — само за класове.
Основни точки
Protocol в Swift — абстрактен интерфейс, определящ изискванията, на които даден тип трябва да отговаря. Протоколът може да изисква свойства (с getter/setter), методи (на инстанция и тип), инициализатори и 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) |
| Риск от свързване | Нисък (слабо свързване) | Висок (твърда йерархия) |
Според 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 (асоцииран тип) — обобщен тип вътре в протокола, който се конкретизира от имплементиращия тип. Това позволява създаването на типобезопасни протоколи без посочване на конкретен тип данни. Асоциираните типове работят заедно с generics на 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 наследяването — протоколите нямат общ прародител.
some (opaque type) гарантира, че функцията връща един конкретен тип, отговарящ на протокола. any (existential type) позволява съхраняване на произволен тип, отговарящ на протокола. some се използва за запазване на идентичността на типа, 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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също