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 (&) работает в параметрах функций, переменных и generic-ограничениях. Компилятор проверяет, что переданный тип одновременно удовлетворяет всем протоколам. Composition часто используется в SwiftUI: some View — это generic с composition.
Protocol Composition предпочтительнее создания иерархии наследования: вместо protocol A: B, C можно принимать B & C непосредственно. Это даёт гибкость и снижает связанность. Composition особенно удобен в параметрах функций и generic-ограничениях, где нужно временно объединить требования без создания промежуточного протокола. Это снижает количество вспомогательных типов в коде.
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 нет abstract классов — их роль выполняют протоколы с extensions.
Да, структуры, классы и enum — все могут принимать протоколы. Это основа POP: вы не обязаны использовать классы для организации архитектуры. Структуры с протоколами дают value semantics и иммутабельность.
Associated type (associatedtype) — placeholder для типа, который реализующий тип определяет самостоятельно. Пример: Collection имеет associatedtype Element. Это generic на уровне протокола.
Да, добавьте наследование от AnyObject: protocol MyProtocol: AnyObject. Тогда только классы смогут принять этот протокол. Это полезно для weak-ссылок и делегатов.
Используйте is для проверки и as? для приведения: if let drawable = item as? Drawable. Это работает только для протоколов без associated types.
Итоги
&) комбинирует протоколы без наследованияany) и opaque types (some) — два способа работы с протоколамиМы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также