Каковы основные различия между протоколом и абстрактным классом в Swift?

Ответ

В Swift протокол определяет контракт (интерфейс), а абстрактный класс — это шаблон для наследования, который сам по себе языком не поддерживается напрямую, но эмулируется. Вот ключевые различия:

Сравнительная таблица

Критерий Протокол (Protocol) Абстрактный класс (Эмуляция)
Наследование Поддерживает множественное наследование (тип может соответствовать многим протоколам). Поддерживает только одиночное наследование.
Кто может использовать Классы, структуры (struct), перечисления (enum). Только классы.
Реализация по умолчанию Есть через расширения (extension). Может содержать реализованные и абстрактные (нереализованные) методы в одном классе.
Хранимые свойства Не может иметь хранимые свойства, только требования. Может иметь хранимые свойства.
Инициализаторы Может требовать инициализатор (init), но не может его реализовать. Может иметь назначенные и convenience инициализаторы.
Тип-значение / ссылка Агностичен (работает и со value, и с reference типами). Работает только с reference типами (классами).

Примеры

// 1. Протокол с расширением для реализации по умолчанию
protocol Vehicle {
    var fuelLevel: Double { get set }
    func startEngine() // Требование
}

extension Vehicle {
    func startEngine() { // Реализация по умолчанию
        print("Engine started for a generic vehicle.")
    }
}

struct Car: Vehicle {
    var fuelLevel: Double
    // startEngine() можно не реализовывать, используется дефолтная версия
}

// 2. Эмуляция абстрактного класса
class AbstractShape {
    // "Абстрактный" метод - требует переопределения
    func area() -> Double {
        fatalError("Subclass must override area()")
    }
    // Конкретный метод
    func description() -> String {
        return "Shape with area: (area())"
    }
}

class Square: AbstractShape {
    let side: Double
    init(side: Double) { self.side = side }
    override func area() -> Double { // Обязательное переопределение
        return side * side
    }
}

// let shape = AbstractShape() // Вызовет fatalError
let square = Square(side: 5)
print(square.description()) // "Shape with area: 25.0"

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

Ответ 18+ 🔞

Ну, слушай, раз уж ты решил влезть в эту тему, то давай разберёмся, что тут к чему, а то некоторые до сих пор путают, как хуй с пальцем. В Swift, блядь, есть протокол — это как договор, контракт, «ты должен уметь вот это и вот то». А абстрактный класс — это такая хитрая эмуляция, потому что Swift его в чистом виде, сука, не поддерживает, но мы же русские, мы везде найдём, как обойти.

Таблица, чтобы не ебать мозг

Критерий Протокол (Protocol) Абстрактный класс (Эмуляция)
Наследование Можешь нацеплять сколько влезет (множественное). Только один родитель, как в жизни — не выбирают.
Кто может юзать Классы, структуры (struct), перечисления (enum) — всем сестрам по серьгам. Только классы, остальные — мимо кассы.
Реализация по умолчанию Да, через расширения (extension), подкинешь готовенькое. Может быть и готовый код, и пустышка, которая кричит «переопредели меня, мудак!».
Хранимые свойства Не может требовать, только описание. Может иметь свои поля, как нормальный класс.
Инициализаторы Может требовать init, но сам не реализует — только указывает пальцем. Может иметь свои init, и назначенные, и convenience.
Тип-значение / ссылка Всё равно, работает и с value, и с reference. Только reference типы (классы), остальным — пиздец.

Примеры, чтобы стало совсем ясно

// 1. Протокол с расширением — красота, а не жизнь
protocol Vehicle {
    var fuelLevel: Double { get set }
    func startEngine() // Требуем, чтобы был такой метод
}

extension Vehicle {
    func startEngine() { // А вот и готовая реализация, бери и пользуйся
        print("Engine started for a generic vehicle.")
    }
}

struct Car: Vehicle {
    var fuelLevel: Double
    // startEngine() можно не писать — возьмём из расширения, ёпта!
}

// 2. Эмуляция абстрактного класса — тут уже посерьёзнее
class AbstractShape {
    // "Абстрактный" метод — если не переопределишь, получишь fatalError
    func area() -> Double {
        fatalError("Subclass must override area(), идиот!")
    }
    // А это уже готовый метод, который юзает тот самый area()
    func description() -> String {
        return "Shape with area: (area())"
    }
}

class Square: AbstractShape {
    let side: Double
    init(side: Double) { self.side = side }
    override func area() -> Double { // Вот тут переопределяем, иначе — писец
        return side * side
    }
}

// let shape = AbstractShape() // Вызовет fatalError — нахуй так делать
let square = Square(side: 5)
print(square.description()) // "Shape with area: 25.0" — вот теперь красота

Вывод, блядь: Протоколы в Swift — это гибко, мощно и модно. Их все любят и используют налево и направо. Абстрактные классы — это такой костыль, когда тебе реально нужна общая база с состоянием для семейства классов. Но в целом, Swift толкает тебя в сторону протоколов, так что не упрямься, иди в ногу со временем, ёпта!