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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также