Интерфейсы и протоколы
Суть
Интерфейс (в Swift и Objective-C — протокол) — контракт: набор требований, которые тип обязан выполнить. Тип, принявший протокол, можно использовать везде, где ожидается этот протокол, — это основа полиморфизма без наследования. В Swift протоколы принимают не только классы, но и struct, enum, actor.
Что умеют протоколы в Swift
- Требования: методы, свойства (
{ get }/{ get set }), инициализаторы,associatedtype, статические члены. - Default-реализации в
extension— конформер может их не писать. Поэтому «нужно реализовать все методы» в Swift неверно. - Наследование протоколов и композиция:
any Codable & Sendable. - Условное соответствие:
extension Array: Drawable where Element: Drawable. - Ограничение на классы:
protocol P: AnyObject— нужно дляweakделегатов.
import Foundation
protocol Identifiable2 {
associatedtype ID: Hashable
var id: ID { get } // property requirement
}
protocol Greeter {
var name: String { get }
func greet() -> String
}
extension Greeter {
// default implementation: conformers may omit it
func greet() -> String { "Hello, \(name)" }
}
struct User: Greeter, Identifiable2 {
let id: UUID = UUID()
let name: String
}
let anyGreeter: any Greeter = User(name: "Ann") // existential box
func show(_ g: some Greeter) { print(g.greet()) } // generic, static dispatch
show(User(name: "Bob")) // Hello, Bob
print(anyGreeter.greet()) // Hello, Ann
any vs some
any P— экзистенциальный контейнер: тип стирается, вызовы через witness table, возможен boxing в кучу. Нужен для гетерогенных коллекций и хранения «какого-то» значения.some P— opaque type: конкретный тип один, известен компилятору, диспетчеризация статическая. Предпочтителен в сигнатурах функций.
На что смотрит интервьюер
- Протокол — инструмент для тестируемости (подмена зависимостей стабами) и развязки модулей.
- Protocol-oriented programming: поведение добавляется через
extensionпротокола, а не через базовый класс. - Ловушка: методы из
extension, не объявленные в протоколе, диспетчеризуются статически.