Ответ
convenience — обозначает вспомогательный (вторичный) инициализатор, который должен внутри вызвать designated (назначенный) инициализатор того же класса. Упрощает создание объекта с альтернативными параметрами или значениями по умолчанию.
required — обязывает все прямые подклассы реализовать данный инициализатор. Гарантирует, что определённая логика инициализации будет доступна во всей иерархии наследования.
Основные отличия:
convenience |
required |
|
|---|---|---|
| Назначение | Упрощение инициализации | Контракт для подклассов |
| Вызов | Должен вызвать self.init |
Может быть как designated, так и convenience |
| Наследование | Может быть переопределён в подклассе | Обязателен для реализации в подклассе |
| Использование | Альтернативные параметры, значения по умолчанию | Протоколы, классовые типы, фабричные методы |
Пример convenience инициализатора:
class Document {
var title: String
var body: String
// Designated инициализатор
init(title: String, body: String) {
self.title = title
self.body = body
}
// Convenience инициализатор
convenience init(title: String) {
self.init(title: title, body: "") // Вызов designated
}
// Ещё один convenience
convenience init() {
self.init(title: "Untitled") // Вызов другого convenience
}
}
let doc1 = Document(title: "Report", body: "Content") // Designated
let doc2 = Document(title: "Note") // Convenience
let doc3 = Document() // Convenience -> Convenience -> Designated
Пример required инициализатора:
class Vehicle {
let wheels: Int
// Все подклассы должны реализовать этот init
required init(wheels: Int) {
self.wheels = wheels
}
}
class Car: Vehicle {
let brand: String
init(brand: String) {
self.brand = brand
super.init(wheels: 4)
}
// Обязательная реализация required инициализатора
required init(wheels: Int) {
self.brand = "Unknown"
super.init(wheels: wheels)
}
}
class Bicycle: Vehicle {
// Тоже должен реализовать required init
required init(wheels: Int) {
super.init(wheels: wheels)
}
}
// Использование с классовой переменной (метаклассом)
func createVehicle(ofType type: Vehicle.Type) -> Vehicle {
return type.init(wheels: 2) // Требуется required init
}
let bike = createVehicle(ofType: Bicycle.self)
Важно:
convenienceинициализатор не может вызвать другойconvenienceинициализатор суперкласса, толькоdesignated.requiredмодификатор часто сочетается сconvenience, если нужен фабричный метод в иерархии.- При переопределении
requiredинициализатора в подклассе также нужно указыватьrequired(а неoverride).
Ответ 18+ 🔞
А, ну вот, опять эти ваши convenience с required! Слушай, давай разберёмся, как есть, без этих ваших академических закидонов.
Представь, что у тебя есть класс, ну, скажем, Пицца. У неё есть главный, матерый инициализатор — designated. Это как заказ пиццы «Маргарита» с полным списком: тесто, сыр, соус, оливкове масло, базилик — всё по полной программе, блядь. Без этого — пиццы нет.
class Пицца {
var тесто: String
var сыр: String
var соус: String
// Вот он, designated, царек, блядь. Без него нихуя.
init(тесто: String, сыр: String, соус: String) {
self.тесто = тесто
self.сыр = сыр
self.соус = соус
}
}
А теперь, сука, convenience — это когда ты ленивая жопа и не хочешь каждый раз указывать весь этот овердохуище параметров. Хочешь просто сказать: «Дайте пиццу "Четыре сыра"» — а там уже внутри само подставится, какой сыр и соус. Удобняшка, блядь!
class Пицца {
var тесто: String
var сыр: String
var соус: String
init(тесто: String, сыр: String, соус: String) {
self.тесто = тесто
self.сыр = сыр
self.соус = соус
}
// А вот convenience — ленивая жопа в действии!
convenience init(название: String) {
switch название {
case "Четыре сыра":
self.init(тесто: "Тонкое", сыр: "Микс", соус: "Сливочный")
case "Пепперони":
self.init(тесто: "Толстое", сыр: "Моцарелла", соус: "Томатный")
default:
self.init(тесто: "Обычное", сыр: "Моцарелла", соус: "Томатный")
}
}
// Или вот ещё ленивее — пицца по умолчанию, а то нихуя не выбрал
convenience init() {
self.init(название: "Маргарита") // Смотри, блядь, вызывает другой convenience!
}
}
Важный момент, ёпта: convenience инициализатор обязан где-то внутри вызвать designated инициализатор того же класса — self.init(...). Не может он просто так, с бухты-барахты, свойства назначить. Иначе компилятор тебе такую ошибку влепит — мало не покажется.
А теперь про required. Это, блядь, уже не про лень, а про жёсткий контракт, ёбаный в рот! Ты как родитель-класс говоришь: «Слушай сюда, все мои будущие дети-подклассы! Какой бы ты, пидарас шерстяной, ни был, у тебя ДОЛЖЕН быть вот этот инициализатор! И точка, нахуй!»
Чаще всего это нужно, когда ты работаешь с классом как с типом (через SomeClass.self) или в протоколах.
class Транспорт {
let колёса: Int
// required, ёпта! Все наследники обязаны это реализовать.
required init(колёса: Int) {
self.колёса = колёса
}
}
class Велосипед: Транспорт {
// Блядь, раз родитель сказал required — делаем, и не рыпайся.
// Заметь, тут даже 'override' не нужен, только required.
required init(колёса: Int) {
super.init(колёса: колёса)
}
}
class Машина: Транспорт {
var марка: String
init(марка: String) {
self.марка = марка
super.init(колёса: 4) // у машины обычно 4 колеса, логично же
}
// А вот и required реализация! Даже если есть свой инициализатор.
required init(колёса: Int) {
self.марка = "Неизвестно"
super.init(колёса: колёса)
}
}
И вот где это, блядь, выстреливает: когда у тесть фабрика или общий код, который создаёт объекты через метакласс.
func сгенерируйТранспорт(типа: Транспорт.Type, колёса: Int) -> Транспорт {
// Без required init тут была бы пизда — компилятор не уверен, что у подкласса он есть.
return типа.init(колёса: колёса) // А так — всё ок, required гарантирует!
}
let велик = сгенерируйТранспорт(типа: Велосипед.self, колёса: 2)
Итожу, блядь:
convenience— это твой ленивый кореш, который всегда ищет короткий путь, но в итоге всё равно зовёт главного (designated).required— это ваш строгий отец, который заставляет всех детей иметь одинаковую семейную черту (инициализатор), чтобы потом не было сюрпризов, нахуй.
И запомни: convenience может вызывать другой convenience, но цепочка ВСЕГДА должна упереться в designated. А required может быть как designated, так и convenience — главное, чтобы в подклассах его реализовали, иначе пиши пропало.