Классы в Swift [Часть 1]

в 7:37, , рубрики: swift, классы, ооп

Недавно Apple представила общественности достаточно важное изменение в разработке iOS приложений, анонсировав новый язык программирования Swift. В настоящее время, количество материалов на русском, посвящённых этому языку, ограничено. Также Swift — язык объектно-ориентированный, и классы в нём — основа основ. Поэтому я решил перевести эту статью.
Классы в Swift [Часть 1]

Создание классов

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

class Point {
    var x = 0.0 // sets the default value of x to 0
    var y = 0.0 // sets the default value of x to 0
}

// this creates a new Point instance using the default initializer
var point = Point()

point.x = 100 // sets the x property to 100
point.y = 200 // sets the y property to 200

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

Из официальной документации Apple:

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

Процесс инициализации реализуется с помощью инициализаторов, которые являются специальными методами, вызывающимися при объявлении новых экземпляров класса. В отличие от Objective-C, в Swift инициализаторы ничего не возвращают, т.к. они обеспечивают правильность инициализации новых экземпляров класса.

Обратимся к примеру

class Point {
    var x
    var y
}

Запустив его, вы получите три ошибки компиляции

class Point { // Class 'Point' has no initializers (класс <code>Point</code> не содержит инициализаторов)
    var x // Type annotation missing in pattern (Отсутствует аннотация типа)
    var y // Type annotation missing in pattern (Отсутствует аннотация типа)
}

Чтобы исправить ситуацию, давайте зададим тип каждого свойства

class Point {
    var x: Double
    var y: Double
}

Инициализатор задаётся ключевым словом init. У инициализатора может быть несколько параметров, а может их вообще не быть

class Point { 
    var x: Float
    var y: Float

    init(x: Float, y: Float) {
        self.x = x
        self.y = y
    }
}

// Example usage
var point = Point(x: 100, y: 200)

Также мы можем установить опциональные значения свойств. Чтобы это сделать, просто поставьте ? после типа, как показано в примере. Если объявить свойство подобным образом, то оно будет иметь значение по умолчанию nil.

class Point { 
    var x: Float?
    var y: Float?
}

var point = Point() // both the x and y properties are now set to nil

point.x = 100.0
point.y = 200.0

Перегрузка инициализаторов

Представим, что во время создания проекта появилась необходимость использовать список пользователей. Давайте для начала создадим класс User. Каждый объект класса будет иметь следующие поля: имя (firstName), фамилию (lastName), краткую информацию о пользователе (bio). Поля имени и фамилии будут иметь опциональные значения, а поле краткой информации — значение по умолчанию (т.е. это поле будет дополнительным).

class User {
    var firstName: String?
    var lastName: String?
    var bio: String = "I ♡ Swift!"
}

var user = User() // user = { firstName: nil, lastName: nil, bio: "I ♡ Swift!"}

Ну что ж, класс мы написали. Теперь пришло время создать первых пользователей. Поле краткой информации — дополнительное, значит нам нужно перегрузить инициализатор, т.к. можно как написать что-то про игрока, так и оставить его тёмной личностью. Ну что ж, давайте напишем инициализаторы для обоих случаев

class User {
    var firstName: String
    var lastName: String
    var bio: String = "I ♡ Swift!"

    // no bio provided
    init(firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }

    // bio provided
    init(firstName: String, lastName: String, bio: String) {
        self.firstName = firstName
        self.lastName = lastName
        self.bio = bio
    }
}

var me = User(firstName: "Andrei", lastName: "Puni")
// me = { firstName: "Andrei", lastName: "Puni", bio: "I ♡ Swift!"}

var silviu = User(firstName: "Silviu", lastName: "Pop", bio: "I f**ing ♡ Swift!!!")
// silviu = { firstName: "Silviu", lastName: "Pop", bio: "I f**ing ♡ Swift!!!"}

Однако согласитесь, это не совсем рационально, ведь отличия в инициализации минимальные — про кого-то есть какая-то информация, а про кого-то — нет. Поэтому давайте напишем один инициализатор, а аргументу bio дадим значение по умолчанию.

class User {
    var firstName: String
    var lastName: String
    var bio: String

    init(firstName: String, lastName: String, bio: String = "I ♡ Swift!") {
        self.firstName = firstName
        self.lastName = lastName
        self.bio = bio
    }
}

var me = User(firstName: "Andrei", lastName: "Puni")
// me = { firstName: "Andrei", lastName: "Puni", bio: "I ♡ Swift!"}

var silviu = User(firstName: "Silviu", lastName: "Pop", bio: "I f**ing ♡ Swift!!!")
// silviu = { firstName: "Silviu", lastName: "Pop", bio: "I f**ing ♡ Swift!!!"}

Идентичность классов

Из официальной документации Apple:

Операторы идентичности

Поскольку класс является ссылочным типом, может возникнуть ситуация, когда один и тот же экземпляр класса обозначается несколькими переменными или константами. (Это невозможно для структур и перечислений, т.к. и те, и другие являются значимыми типами и копируются при присваивании и передаче в функцию в качестве параметров)

Иногда полезно выяснить, что две переменные или константы ссылаются на один и тот же экземпляр класса. Для этого в Swift существуют два оператора:
Идентичны (===)
Не идентичны (!==)

Предположим, что у нас есть список игроков, один из них — владелец замка. Нам необходимо добавить какие-то функции для игроков, не являющихся владельцами замка. Для этого давайте используем оператор идентичности (===)

var users: User[] = [ ... ] // User[] means Array of Users
var host = /* some user */ 


for user in users {
    if user === host {
        // host logic here
        println("this is the host")
    } else {
        // guest logic here
        println("this is a guest")
    }
}

Оператор равенства == не работает при сравнении объектов классов, так что вам не следует бояться подобных ошибок.

В следующей части мы рассмотрим наследование классов и протоколы.

Автор: DrhF

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js