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

Original author: Andrei Puni
  • Translation
  • Tutorial
Недавно Apple представила общественности достаточно важное изменение в разработке iOS приложений, анонсировав новый язык программирования Swift. В настоящее время, количество материалов на русском, посвящённых этому языку, ограничено. Также Swift — язык объектно-ориентированный, и классы в нём — основа основ. Поэтому я решил перевести эту статью.



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


Для создания новых классов используется ключевое слово 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")
    }
}


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

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

Only registered users can participate in poll. Log in, please.

Полезен ли перевод для вас?

  • 57.6%Да, перевод оказался полезен174
  • 9.9%Нет, перевод бесполезен30
  • 9.9%Не могу ответить однозначно30
  • 22.5%Не интересуюсь Swift68
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 16

    +1
    Спасибо за перевод, но на мой взгляд все абсолютно понятно только по одному коду, даже если программист совсем не знает английский язык.
    Лучшим решением было бы не переводить такие простые вещи, а собирать дайджесты по Swift, на мой взгляд.
      0
      Кстати, в Swift есть динамические возможности из Objective C? Было бы интересно посмотреть, как они реализованы в новом языке с учетом опыта других языков программирования.
        +1
        Swift работает на рантайме Objective C. Однако все не так просто: в общем случае(если не указывать атрибут objc) имена классов мангляться. Когда я проводил свои эксперименты, я даже не совсем понял, во что превращаются свойства, ибо если добавить свойство в класс, то никаких ivar'ов по итогу у него не появлялось(думаю, логично предположить, что значения свойств как и в Obejctive C хранятся в ivar'ах). Вообще немного об этом можно почитать у Mike Ash www.mikeash.com/pyblog/friday-qa-2014-07-18-exploring-swift-memory-layout.html
          0
          Если указать @­objc то имена все равно манглятся
            0
            Вот и снова ценность поста почти целиком состоит из ценности комментария к нему.
            Спасибо за ссылку!
          –10
          Жду с нетерпением языка с таким вот оператором сравнения:

          a ================================================================================================== b
          


          Ну серьезно, куда уж три то равно… понимаю еще два, но три…
            +2
            Вы ж в курсе что там есть возможность создавать свои операторы? И люди создают, не знаю для фану, или просто от «молодости»…
              0
              Дядя книжки пишет, не думаю, что тут дело в «молодости».
                –1
                Ну, это не показатель, имхо
              +4
              Ну оператора строгого соответствия не они придумали, во многих, если не во всех, ОО программных языках он есть.
                0
                Привет от не строго типизированных языков:)
                  0
                  Да ладно. Только не говорите, что Вы до сих пор не знали о том, что 'тройное равно' есть в PHP и JS.
                    0
                    Люди на javascript же пишут так и ничего, не умер никто.
                    0
                    При вызове методов обязательно ли писать имя переменной значение которой передается в функцию, например вместо point.move(x: 10, y: 20) написать point.move(10, 20)?

                    Можно ли менять порядок указания значений:
                    point.move(y: 20, x: 10);

                    сработает ли такая конструкция

                    point.move(x: Float = 0, y: Float = 0);

                    point.move(y: 66);

                    Спасибо.
                      –1
                      1. Использование point.move(10, 20) вызовет ошибку компиляции (external names are required), но можно написать так point.move(10, y: 20) (но только в том случае, если первый аргумент не имеет значения по умолчанию).
                      2. Менять порядок указания нельзя — первым должен указываться тот аргумент, который является первым в объявлении метода.
                      3. Конструкция point.move(x: Float = 0, y: Float = 0) не сработает
                      4. Конструкция point.move(y: 66) сработает если аргумент x имеет значение по умолчанию.

                      Offtop: точка с запятой (;) в конце необязательна, она указывается если в одной строке есть две операции. Пример:
                      self.x = x; self.y = y
                        0
                        Вот только начал изучать Swift и вот Ваш offtop прочитал. Интересная вещь. С одной стороны логична, а с другой нет. И вот почему: Есть ли(будут ли) в swift`e такие ситуации, когда одна строка может растянутся на две(как это случалось допустим в c#)?

                    Only users with full accounts can post comments. Log in, please.