Может ли функция в протоколе Swift быть необязательной (optional)?

Ответ

Да, но с ограничениями. Нативно Swift-протоколы требуют реализации всех членов. Необязательные методы требуют подхода @objc.

1. Через @objc (Objective-C совместимость):

  • Протокол и метод помечаются как @objc.
  • Протокол могут принимать только классы (не структуры или перечисления).

    @objc protocol DataSource {
        func requiredMethod()
        @objc optional func optionalMethod() // Необязательный метод
    }
    
    class MyDataSource: DataSource {
        func requiredMethod() { /* Обязательная реализация */ }
        // optionalMethod() можно не реализовывать
    }
    
    // Вызов с опциональной цепочкой
    let source = MyDataSource()
    source.optionalMethod?()

2. Нативный Swift-подход (рекомендуется): Используйте расширения протокола (protocol extension) для предоставления реализации по умолчанию. Метод становится "условно обязательным" — тип может использовать реализацию по умолчанию или предоставить свою.

    protocol Renderable {
        func draw()
    }
    // Реализация по умолчанию
    extension Renderable {
        func draw() { print("Default drawing") }
    }

    struct Circle: Renderable {} // Использует draw() по умолчанию
    struct Square: Renderable {
        func draw() { print("Drawing a square") } // Своя реализация
    }

Ответ 18+ 🔞

А, ну это же классика, блядь! Опять про эти ваши протоколы с необязательными методами. Ну, слушай, тут два пути, как в анекдоте: один в жопу, другой — в библиотеку.

Первый способ — через @objc, старый дедовский, из Objective-C. Тут всё просто, как три копейки: протокол и метод надо пометить @objc. Но есть подвох, ёпта! Только классы могут такое подписать, никаких там структур или перечислений — нихуя.

@objc protocol DataSource {
    func requiredMethod()
    @objc optional func optionalMethod() // Вот он, необязательный, сука!
}

class MyDataSource: DataSource {
    func requiredMethod() { /* Тут без вариантов, делай */ }
    // А optionalMethod() можешь на хуй послать, не реализовывать
}

// Вызывать потом — с опаской, через опциональную цепочку, а то наебнёшься
let source = MyDataSource()
source.optionalMethod?()

Второй способ — нативный, свифтовый, правильный. Тут уже без этого старого хлама. Берёшь расширение протокола (protocol extension) и делаешь реализацию по умолчанию. Получается метод как бы есть, но его можно и не трогать, если не хочешь. Хитрая жопа, но работает.

protocol Renderable {
    func draw()
}
// Подкидываем дефолтную реализацию, чтоб не париться
extension Renderable {
    func draw() { print("Default drawing") }
}

struct Circle: Renderable {} // Сидит себе, использует draw() по умолчанию, и доволен
struct Square: Renderable {
    func draw() { print("Drawing a square") } // А этот умник свою реализацию впендюрил
}

Вот и вся магия. Первый способ — для совместимости со старым кодом, второй — для чистого Swift, чтобы мозги не ебать. Выбирай, что душе угодно.