self.init
для ссылки на другие инициализаторы того же типа-значения, когда Вы пишите свои собственные инициализаторы. Вы можете вызвать self.init
только из инициализатора.
Size
и Point
, каждая из которых представляет значения по-умолчанию 0.0 для всех своих свойств:
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
Rect
одним из трёх способов - использованием нуль-заданных значений свойств origin
и size
, предоставлением специального размера и точки начала или предоставлением специальной центровой точки и размера. Эти варианты инициализации представлены тремя инициализаторами, которые являются частью определения структуры Rect
:
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
Rect
- init()
- функционально идентичен тому, что получить структура по-умолчанию, если не будет иметь своих собственных конструкторов. Этот конструктор имеет пустое тело, что представляется пустой парой фигурных скобок {}. Вызов этого конструктора вернёт объект типа Rect
, чьи свойства origin
и size
оба имеют значения по-умолчанию: Point(x: 0.0, y: 0.0)
и Size(width: 0.0, height: 0.0)
из их определений свойств:
let basicRect = Rect()
// начало координат basicRect равно (0.0, 0.0) и его размеры равны (0.0, 0.0)
init(origin:size:)
функционально идентичен конструктору почленному, который структура получила бы, если бы не имела своих собственных конструкторов. Этот конструктор просто присваивает значения аргументов origin
и size
соответствующим хранимым свойствам:
let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
// начало координат originRect равно (2.0, 2.0) и его размеры (5.0, 5.0)
init(center:size:)
более сложен. Он начинается с вычисления подходящего центра координат, основываясь на точке center
и значении size
. Затем он вызывает (или делегирует) управление конструктору init(origin:size:)
, который сохраняет новые значения центра координат и размеров в соответствующие свойства:
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// начало координат centerRect равно (2.5, 2.5) и его размеры равны (3.0, 3.0)
Конструктор init(center:size:)
мог бы самостоятельно присвоить новые значения origin
и size
соответствующим свойствам. Однако более удобно (и более просто для понимания) для конструктора init(center:size:)
воспользоваться преимуществами существующего конструктора, который уже предлагает тот же функционал.
init
, разделённые пробелом.
self
в качестве значения до тех пор, пока первая фаза инициализации не будет выполнена.
willSet
и didSet
свойств надкласса вызываются, когда свойство устанавливается в конструкторе подкласса после вызова конструктора надкласса. Они не вызываются, когда класс устанавливает свои собственные свойства перед вызовом инициализатора суперкласса.
override
перед определением инициализатора подкласса. Это верно, даже если Вы перезаписываете автоматически предоставленный инициализатор по-умолчанию, как это описано в {Инициализаторах по-умолчанию}.
override
заставляет Swift проверить, имеет ли надкласс совпадающий основной конструктор, и проверяет их совпадение.
override
, когда перезаписываете основной инициализатор надкласса, даже если реализация Вашим подклассом этого инициализатора есть вспомогательный инициализатор.
override
, кода Вы предоставляете совпадающую реализацию для вспомогательного инициализатора надкласса.
Vehicle
. Этот базовый класс определяет хранимое свойство с названием numberOfWheels
со значением по-умолчанию типа Int
, равным 0. Свойство numberOfWheels
используется вычисляемым свойством description
для создания описания типа String
характеристик транспорта:
class Vehicle {
var numberOfWheels = 0
var description: String {
return "\(numberOfWheels) wheel(s)"
}
}
Vehicle
предоставляет значение по-умолчанию для его единственного хранимого свойства и не предоставляет никаких специальных конструкторов. В результате он автоматически получает инициализатор по-умолчанию. Этот дефолтный инициализатор (когда он доступен) всегда выступает основным инициализатором для класса и может быть использован для создания нового объекта типа Vehicle
со значением numberOfWheels
, равным 0:
let vehicle = Vehicle()
print("Vehicle: \(vehicle.description)")
// Vehicle: 0 wheel(s)
Bicycle
класса Vehicle
:
class Bicycle: Vehicle {
override init() {
super.init()
numberOfWheels = 2
}
}
Подкласс Bicycle
определяет специальный основной конструктор init()
. Этот основной инициализатор совпадает с основным конструктором суперкласса для Bicycle
, так что версия этого конструктора у Bicycle
помечена модификатором override
.
init()
для Bicycle
начинается с вызова super.init()
, который вызывает дефолтный конструктор для надкласса класса Bicycle
- Vehicle
. Это гарантирует, что унаследованное свойство numberOfWheels
инициализируется классом Vehicle
прежде, чем класс Bicycle
получает возможность изменить это свойство. После вызова super.init()
изначальное значение numberOfWheels
заменяется новым значением 2.
Bicycle
, Вы сможете вызвать его унаследованное вычисляемое свойство description
для того, чтобы увидеть, как изменилось его свойство numberOfWheels
:
let bicycle = Bicycle()
print("Bicycle: \(bicycle.description)")
// Bicycle: 2 wheel(s)
Подклассы могут изменять унаследованные переменные свойства в процессе инициализации, но не могут изменять константные свойства.
Food
, RecipeIngredient
и ShoppingListItem
и демонстрирует, как взаимодействуют их конструкторы.
Food
:
Food
, который является простым классом для инкапсуляции названия еды. Класс Food
вводит единственное свойство name типа String
и предоставляет два конструктора для создания объектов типа Food
:
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
Food
предоставляет основной инициализатор, который принимает один аргумент с названием name
. Этот конструктор может быть использован для создания нового объекта типа Food
со специфическим именем:
let namedMeat = Food(name: "Bacon")
// имя namedMeat равно "Bacon"
Конструктор init(name: String)
класса Food
представлен в качестве основного инициализатора, так как он убеждается, что все хранимые свойства нового объекта типа Food
полностью проинициализированы. Класс Food
не имеет надкласса, так что конструктору init(name: String)
не нужно вызывать super.init()
для завершения своей инициализации.
Food
также предоставляет вспомогательный конструктор init()
без аргументов. Конструктор init()
предоставляет стандартное замещающее имя для любой новой еды, путём делегации в конструктор класса init(name: String)
значение имени name величины [Unnamed]
:
let mysteryMeat = Food()
// имя mysteryMeat равно "[Unnamed]"
Food
с названием RecipeIngredient
. Класс RecipeIngredient
моделирует ингредиент в поваренном рецепте. Он представляет свойство Int
с названием quantity
(в дополнение к свойству name
, которое он наследует от Food
) и определяет два новых инициализатора для создания объектов типа RecipeIngredient
:
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
RecipeIngredient
:
RecipeIngredient
имеет единственный основной конструктор с названием init(name: String, quantity: Int)
, который может быть использован для задания всех свойств нового объекта типа RecipeIngredient
. Этот конструктор начинает свою работу с присваивания переданного аргумента quantity
одноимённому свойству, которое является единственным новым свойством, представленным в RecipeIngredient
. После этого конструктор делегирует вверх конструктору init(name: String)
класса Food
. Этот процесс удовлетворяет проверки 1 из {Двухфазовой инициализации} выше.
RecipeIngredient
также определяет вспомогательный инициализатор init(name: String)
, который используется для создания объекта RecipeIngredient
только по его имени. Этот вспомогательный инициализатор принимает, что количество равно 1 для каждого объекта типа RecipeIngredient
, создаваемого без явного указания количества. Определение этого вспомогательного конструктора делает объекты RecipeIngredient
более быстрыми и более удобными для создания и избегают дублирования кода при создания нескольких объектов с единичным количеством типа RecipeIngredient
. Этот вспомогательный инициализатор просто делегирует управление основному инициализатору класса, передавая в него количество 1.
init(name: String)
, представленный в RecipeIngredient
, принимает те же параметры, что и основной инициализатор у Food
. Ввиду этого этот вспомогательный инициализатор перезаписывает основной инициализатор своего надкласса, а значит он должен быть мочен модификатором override
.
RecipeIngredient
предоставляет инициализатор init(name: String)
в качестве удобного инициализатора, RecipeIngredient
предоставляет имплементацию для всех основных инициализаторов надкласса. Следовательно RecipeIngredient
автоматически унаследует также все вспомогательные инициализаторы надкласса.
RecipeIngredient
- это Food
, который имеет вспомогательный инициализатор init()
. Этот инициализатор наследуется RecipeIngredient
. Унаследованная версия init()
функционирует тем же способом, что и его версия в Food
, исключая то, что она делегирует RecipeIngredient-версии конструктора init(name: String)
вместо версии Food
.
RecipeIngredient
:
let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
RecipeIngredient
с названием ShoppingListItem
. ShoppingListItem-класс моделирует ингредиент рецепта в форме его появления в списке покупок.
ShoppingListItem
представляет Булево/ свойство с названием purchased
и изначальным значением false
. ShoppingListItem
также добавляет вычисляемое свойство description
, которое предоставляет текстовое описание объекта ShoppingListItem
:
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " ✔" : " ✘"
return output
}
}
ShoppingListItem
не определяет конструктора для предоставления изначального значения для purchased
, так как вещи в листе покупок (как это смоделировано здесь) всегда начинают свой жизненный путь некупленными.
ShoppingListItem
автоматически наследует все основные и вспомогательные инициализаторы своего надкласса.
ShoppingListItem
:
var breakfastList = [
ShoppingListItem(),
ShoppingListItem(name: "Bacon"),
ShoppingListItem(name: "Eggs", quantity: 6),
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
print(item.description)
}
// 1 x Orange juice ✔
// 1 x Bacon ✘
// 6 x Eggs ✘
Здесь новый массив с названием breakfastList
создан из литерала массива, содержащего три объекта типа ShoppingListItem
. Тип этот массива выведен в [ShoppingListItem]
. После создания массива имя первого элемента ShoppingListItem
массива заменяется c "[Unnamed]" на "Orange juice", и он маркируется в качестве приобретенного. Вывод описания каждого элемента в массива показывает, что их изначальные состояния были заданы, как ожидалось.