Protocol — что это такое, протоколы и делегаты в iOS

Автор: IT Sectr Опубликовано: 2026-02-18 Время чтения: 10 мин

Protocol — это набор требований (свойства и методы), которым должен соответствовать тип, реализующий данный протокол. В Swift протоколы — центральный элемент Protocol-Oriented Programming (POP), позволяющий реализовать полиморфизм без наследования. По данным Swift.org (2025), протоколы используются в 85% типов стандартной библиотеки Swift. В Objective-C @protocol выполняет схожую роль, но с ограничением — только для классов.

Главное

  • Protocol — контракт, определяющий интерфейс, который должна реализовать структура, класс или перечисление
  • Protocol-Oriented Programming — парадигма Swift, где протоколы и расширения протоколов заменяют глубокую иерархию наследования
  • Protocol extension — реализация методов по умолчанию, делающая методы протокола опциональными без @objc
  • Associated types — обобщённые протоколы с ассоциированными типами для типобезопасной работы с разными типами данных
  • Protocol composition — комбинирование нескольких протоколов через оператор & для точного описания требований

Что такое протокол в Swift?

Protocol в Swift — это абстрактный интерфейс, определяющий требования, которым должен удовлетворять тип. Протокол может требовать свойства (с геттером/сеттером), методы (экземпляра и типа), инициализаторы и subscript. В отличие от классов, протоколы могут быть реализованы структурами, перечислениями и классами — это даёт гибкость, недоступную в чисто классовых языках.

Swift
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: парадигма Swift

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 — ключевая причина этого сдвига: протоколы позволяют структурам получать полиморфное поведение без перехода на классы.

Protocol vs abstract class vs interface

Протоколы Swift занимают промежуточное положение между интерфейсами Java и абстрактными классами C++. Они могут содержать реализацию (через extension), но не имеют состояния (хранимых свойств). Разберём отличия на примере трёх языков.

ХарактеристикаSwift ProtocolJava InterfaceC++ Abstract Class
Реализация методовДа (extension)Да (default methods)Да
Хранимые свойстваНетНетДа
Value typesДаНетНет
Множественная реализацияДаДаДа
ИнициализаторыДа (требования)НетДа

Ключевое отличие: Swift Protocol может требовать инициализаторы и subscript, что недоступно в Java Interface. При этом протокол не может хранить состояние — это остаётся прерогативой типа, реализующего протокол.

Associated Types и Generics в протоколах

Associated Type (ассоциированный тип) — это обобщённый тип внутри протокола, который конкретизируется реализующим типом. Это позволяет создавать типобезопасные протоколы без указания конкретного типа данных. Ассоциированные типы работают в паре с дженериками Swift.

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 и расширения протоколов

Protocol composition — комбинирование нескольких протоколов через оператор &. Тип, соответствующий композиции, должен реализовать все объединённые протоколы. Это заменяет множественное наследование, отсутствующее в Swift, и позволяет точно специфицировать требования к параметрам функции.

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 — предшественник Swift Protocol, но с существенными ограничениями. Objective-C протоколы доступны только для классов (не для структур или перечислений) и используют динамическую диспетчеризацию через message passing. Методы могут быть @required (по умолчанию) или @optional.

Objective-C
@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 может содержать поля с данными. Protocol может быть реализован структурами и перечислениями, abstract class — только классами. В Swift протоколы — основной инструмент абстракции, классы используются реже.

Что такое Protocol-Oriented Programming?

POP — парадигма, где протоколы и расширения протоколов заменяют глубокие иерархии наследования. Вместо базового класса, от которого наследуют все подклассы, POP использует композицию протоколов с реализациями по умолчанию через extension. Это снижает связанность и повышает переиспользование кода.

Может ли протокол наследовать другой протокол?

Да, протоколы Swift поддерживают наследование. protocol SerializableDrawable: Drawable, Codable — протокол, объединяющий требования Drawable и Codable. Тип, реализующий SerializableDrawable, должен выполнить требования всех протоколов в иерархии. Это отличается от class inheritance — протоколы не имеют общего предка.

Что такое any и some в контексте протоколов?

some (opaque type) гарантирует, что функция возвращает один конкретный тип, соответствующий протоколу. any (existential type) позволяет хранить любой тип, соответствующий протоколу. some используется для сохранения identity типа, any — для гетерогенных коллекций. some появился в Swift 5.1, any — в Swift 5.7.

Как проверить соответствие протоколу в Swift?

Используйте is для проверки и as? для приведения: if let drawable = object as? Drawable { drawable.draw(in: ctx) }. В Objective-C используется conformsToProtocol:. Swift также поддерживает is-проверку для протоколов без associated types.

Итоги

  • Protocol — контракт, определяющий требования к свойствам, методам, инициализаторам и subscript для реализующего типа
  • Protocol-Oriented Programming заменяет классовое наследование композицией протоколов с расширениями
  • Protocol extension предоставляет реализацию по умолчанию, делая методы опциональными без @objc
  • Associated types позволяют создавать обобщённые протоколы с конкретизацией типа на стороне реализации
  • Protocol composition через & объединяет требования нескольких протоколов
  • Objective-C @protocol ограничен классами и не поддерживает associated types, generics и value types
  • Рекомендация: используйте протоколы как основной инструмент абстракции в Swift, применяя классы только при необходимости reference semantics

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также