Инициализаторы


Инициализация представляет процесс подготовки объекта класса, структуры или перечисления к использованию. Этот процесс может включать установку начальных значений для свойств класса.

Для создания объекта класса используется инициализатор. Каждый класс имеет инициализатор по умолчанию:

1
2
3
4
5
6
7
class User {

var age: Int = 0
var name: String = ""
}

var tom: User = User()
Выражение User() преставляет вызов инициализатора.

Важно, что хранимые свойства класса (то есть переменные и константы) должны быть инициализированы и иметь определенное значение ко времени создания объекта класса. В данном случае свойствам класса name и age напрямую присваиваются значения. Но также для инициализации свойств может использоваться инициализатор.

Для переопределения инициализатора в классе нам надо использовать ключевое слово init:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class User {

var age: Int
var name: String

init(){

age = 22
name = "Tom"
}

func getUserInfo(){

print("Имя: \(name); возраст: \(age)")
}
}

var tom: User = User()
tom.getUserInfo() // Имя: Tom; возраст: 22
Стоит отметить, что так как переменным name и age не присваиваются начальные значения, а их инициализация производится в инициализаторе, то можно определить эти переменные как константы:

1
2
3
4
5
6
7
8
9
10
11
class User {

let age: Int
let name: String

init(){

age = 22
name = "Tom"
}
}
Фактически инициализатор представляет функцию, которая выполняет начальную инициализацию объекта.

При необходимости мы можем определять дополнительные инициализаторы:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class User {

var age: Int
var name: String

init(){

age = 22
name = "Tom"
}
init(name: String, age: Int){

self.age = age
self.name = name
}

func getUserInfo(){

print("Имя: \(self.name); возраст: \(self.age)")
}
}

var bob: User = User(name: "Bob", age: 34)
bob.getUserInfo() // Имя: Bob; возраст: 34
Второй инициализатор принимает два параметра name и age для установки свойств класса. Так как параметры и свойства класса называются одинаково, то для их разграничения вместе с названиями свойств используется ключевое слово self.

И при создании объекта в данном случае используется второй инициализатор: var bob: User = User(name: "Bob", age: 34)

Инициализаторы могут определять значения по умолчанию для параметров. Так, пример выше мы могли бы сократить следующим образом:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class User {

var age: Int
var name: String

init(name: String = "Tom", age: Int = 22){

self.age = age
self.name = name
}

func getUserInfo(){

print("Имя: \(self.name); возраст: \(self.age)")
}
}
var tom = User()
tom.getUserInfo() // Имя: Tom; возраст: 22
Делегирование инициализации
Одни инициализаторы могут вызывать другие. Вызывающие инициализаторы должны быть определены с ключевым словом convenience:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class User {

var age: Int
var name: String

convenience init(){

self.init(name: "Tom", age: 22)
}
init(name: String, age: Int){

self.age = age
self.name = name
}

func getUserInfo(){

print("Имя: \(self.name); возраст: \(self.age)")
}
}

var tom: User = User()
tom.getUserInfo() // Имя: Tom; возраст: 22
Failable-инициализаторы
Специальная разновидность инициализаторов (Failable Initializer) позволяет возвратить значение nil, если в процессе инициализации объекта произошла какая-нибудь ошибка. Например:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User{

var name: String
var age: Int
init?(name: String, age: Int){

self.name = name
self.age = age
if(age < 0){
return nil
}
}
}
var bob: User = User(name: "Bob", age: 34)!
print(bob.name) // Bob
Поскольку пользователь, представленный классом User, в принципе не может иметь возраст меньше нуля. Поэтому ситуация, когда для возраста передается число меньше нуля, может рассматриваться как ошибочная. И в этом случае мы как раз можем использовать failable-инициализатор.

Для определения такого инициализатора после слова init ставится знак вопроса, а в самом инициализаторе можно предусмотреть ситуацию, при которой он возвращает значение nil:

1
2
3
4
5
6
7
8
init?(name: String, age: Int){

self.name = name
self.age = age
if(age < 0){
return nil
}
}
Возвращая nil, мы тем самым указываем, что мы не можем создать объект User по тем данным, которые переданы в инициализатор.

Важно учитывать, что объект, создаваемый этим инициализатором, будет представлять не тип User, а тип User?. Поэтому для получения значения нам надо еще использовать операцию ! (восклицательный знак):

1
var bob: User = User(name: "Bob", age: 34)!
Либо мы можем напрямую работать с объектом User?:

1
var bob: User? = User(name: "Bob", age: 34)
Однако надо учитывать, что если мы передадим неправильные данные, то инициализатор возвратит nil, и получение значение окончится ошибкой. Поэтому в таких случаях перед использованием объекта мы можем проверять на наличие значения:

1
2
3
if let lora = User(name: "Lora Palmer", age: -4){
print(lora.name)
}