Всегда ли нужно явно объявлять инициализатор для класса в Swift?

«Всегда ли нужно явно объявлять инициализатор для класса в Swift?» — вопрос из категории Swift Core, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, явный инициализатор не обязателен, если выполняются оба условия:

  1. Все stored-свойства класса имеют значения по умолчанию.
  2. Класс не наследуется от другого класса, у которого есть отсутствующий designated (назначенный) инициализатор.

В этом случае Swift автоматически создает для класса пустой init().

Пример 1: Инициализатор не требуется

class UserProfile {
    var name: String = "Guest" // Значение по умолчанию
    var age: Int = 0           // Значение по умолчанию
    // Компилятор предоставляет init() автоматически
}
let profile = UserProfile() // Работает

Пример 2: Инициализатор обязателен

class Person {
    var name: String // Нет значения по умолчанию!
    var age: Int     // Нет значения по умолчанию!

    // Должны объявить инициализатор вручную
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}
// let person = Person() // Ошибка: отсутствуют аргументы
let person = Person(name: "Alice", age: 30) // Корректно

Важные отличия от структур:

  • Структуры автоматически получают memberwise инициализатор init(property1:, property2:), даже если свойства не имеют значений по умолчанию.
  • Классы memberwise инициализатор не получают. Его нужно писать вручную.

Наследование и инициализаторы: Если класс-родитель не имеет designated инициализатора без параметров (или он недоступен), то класс-потомок должен предоставить свой собственный designated инициализатор, который правильно инициализирует все свойства, включая унаследованные.

class Vehicle {
    let wheels: Int
    init(wheels: Int) { self.wheels = wheels } // Нет init()
}

class Car: Vehicle {
    var brand: String
    // Обязаны вызвать designated инициализатор родителя
    init(brand: String) {
        self.brand = brand
        super.init(wheels: 4) // Вызов обязателен
    }
}