Protocol в Swift — е договор, който дефинира набор от изисквания, на които всеки тип, който го приеме, трябва да отговаря. Протоколите са в основата на протоколно-ориентираното програмиране (POP) — парадигма, препоръчвана от Apple за Swift заедно с класическия ООП. Според Apple Documentation, 2026, структурите, класовете и enum могат да приемат протоколи, което прави архитектурата гъвкава и тестваема.
Основни точки
Protocol — е абстрактен интерфейс, който определя какво трябва да може да прави даден тип, но не и как го прави. В Swift протоколът е аналог на интерфейсите от Java или Go, но с допълнителни възможности.
Протоколът може да изисква:
{ get } или { get set }Според WWDC 2015, Apple представи Protocol-Oriented Programming като фундаментален подход към архитектурата на Swift приложения. За разлика от ООП, където наследяването на класове създава твърди йерархии, POP предлага композиция на протоколи. Това дава гъвкавост: един тип може да отговаря на няколко протокола, получавайки техните изисквания и реализации чрез extensions.
Protocol се декларира с ключовата дума protocol с име и тяло.
protocol Drawable {
func draw(context: CGContext)
var boundingBox: CGRect { get }
}
Типът приема протокола чрез двоеточие след името:
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. Компилаторът проверява дали всички изисквания на всеки протокол са изпълнени.
Property requirements се задават с ключовата дума var и спецификатори за достъп { get } или { get set }.
protocol UserProtocol {
var name: String { get }
var age: Int { get set }
static var maxAge: Int { get }
mutating func updateName(_ newName: String)
}
Ключовата дума mutating в протокола означава, че методът може да променя self. Структурите трябва да имплементират такъв метод като mutating, класовете могат да го пропуснат. Method requirements се задават с пълен подпис, включително етикети на параметрите.
Protocol може да наследи друг протокол, добавяйки нови изисквания. Това създава йерархия от договори без твърда обвързаност с класове.
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 — механизъм, който позволява да се зададе, че тип трябва да отговаря на няколко протокола едновременно, без да се създава нов комбиниран протокол.
func render(_ item: Drawable & Animatable) {
item.draw(context: ...)
item.animate(duration: 0.3)
}
Composition (&) работи в параметри на функции, променливи и генерични ограничения. Компилаторът проверява дали предаденият тип едновременно удовлетворява всички протоколи. Composition се използва често в SwiftUI: some View — това е генерик с composition.
Protocol Composition се предпочита пред създаването на йерархия на наследяване: вместо protocol A: B, C може директно да се приеме B & C. Това дава гъвкавост и намалява свързаността. Composition е особено удобен в параметри на функции и генерични ограничения, където трябва временно да се комбинират изисквания без създаване на междинен протокол. Това намалява броя на помощните типове в кода.
Protocol може да се използва като тип на променлива, параметър на функция или елемент на колекция. Това се нарича existential type.
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.
При работа с protocol разработчиците често допускат няколко повтарящи се грешки.
Drawable вместо <T: Drawable> там, където е необходим конкретен типAnyObject без необходимост, което изключва struct и enumЧесто задавани въпроси
Protocol дефинира само изисквания без имплементация (до protocol extensions). Abstract class може да съдържа имплементация и състояние. В Swift няма абстрактни класове — тяхната роля се изпълнява от протоколи с extensions.
Да, структурите, класовете и enum — всички могат да приемат протоколи. Това е основата на POP: не сте задължени да използвате класове за организиране на архитектурата. Структурите с протоколи осигуряват семантика на стойност и неизменяемост.
Associated type (associatedtype) — placeholder за тип, който имплементиращият тип определя сам. Пример: Collection има associatedtype Element. Това е генерик на ниво протокол.
Да, добавете наследяване от AnyObject: protocol MyProtocol: AnyObject. Тогава само класове могат да приемат този протокол. Това е полезно за weak референции и делегати.
Използвайте is за проверка и as? за преобразуване: if let drawable = item as? Drawable. Това работи само за протоколи без associated types.
Резюме
&) комбинира протоколи без наследяванеany) и opaque types (some) — два начина на работа с протоколиЩе разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също