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 — абстрактен интерфейс, определящ изискванията, на които даден тип трябва да отговаря. Протоколът може да изисква свойства (с getter/setter), методи (на инстанция и тип), инициализатори и 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)
Риск от свързванеНисък (слабо свързване)Висок (твърда йерархия)

Според 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 (асоцииран тип) — обобщен тип вътре в протокола, който се конкретизира от имплементиращия тип. Това позволява създаването на типобезопасни протоколи без посочване на конкретен тип данни. Асоциираните типове работят заедно с generics на 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 — само от класове. В Swift протоколите са основният инструмент за абстракция, класовете се използват по-рядко.

Какво е Protocol-Oriented Programming?

POP — парадигма, при която протоколите и разширенията на протоколи заменят дълбоките йерархии на наследяване. Вместо базов клас, от който наследяват всички подкласове, POP използва композиция на протоколи с имплементации по подразбиране чрез extension. Това намалява свързаността и повишава повторната употреба на код.

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

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

Какво представляват any и some в контекста на протоколите?

some (opaque type) гарантира, че функцията връща един конкретен тип, отговарящ на протокола. any (existential type) позволява съхраняване на произволен тип, отговарящ на протокола. some се използва за запазване на идентичността на типа, 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 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също