Видеокурсы по изучению языка программирования Swift. Подробнее

Методы экземпляра

Если вы нашли опечатку в тексте, выделите ее и нажмите CTRL + ENTER.

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

Вы пишите метод экземпляра внутри фигурных скобок типа, которому он принадлежит. Метод экземпляра имеет неявный доступ ко всем остальным методам экземпляра и свойствам этого типа. Метод экземпляра может быть вызван только для конкретного экземпляра типа, которому он принадлежит. Его нельзя вызвать в изоляции, без существующего экземпляра.

Ниже пример, который определяет простой класс Counter, который может быть использован для счета количества повторений действия:

class Counter {
    var count = 0
    func increment() {
        count += 1
    }
    func increment(by amount: Int) {
        count += amount
    }
    func reset() {
        count = 0
    }
}

Класс Counter() определяет три метода экземпляра:

  • increment увеличивает значение счетчика на 1
  • increment(by: Int) увеличивает значение счетчика на определенное значение amount.
  • reset() сбрасывает значение счетчика на 0.

Класс Counter так же определяет переменное свойство count, для отслеживания значения счетчика.

Вы можете вызвать методы экземпляра с тем же точечным синтаксисом:

let counter = Counter()
// начальное значение counter равно 0
counter.increment()
// теперь значение counter равно 1
counter.increment(by: 5)
// теперь значение counter равно 6
counter.reset()
// теперь значение counter равно 0

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

Свойство self

Каждый экземпляр типа имеет неявное свойство self, которое является абсолютным эквивалентом самому экземпляру. Вы используете свойство self для ссылки на текущий экземпляр, внутри методов этого экземпляра.

Метод increment может быть вызван так:

func increment() {
    self.count += 1
}

На практике вам не нужно писать self очень часто. Если вы не пишите self, то Swift полагает, что вы ссылаетесь на свойство или метод текущего экземпляра каждый раз, когда вы используете известное имя свойства или метода внутри метода. Это хорошо видно при использовании свойства count (а не self.count) внутри трех методов Counter.

Главное исключение из этого правила получается, когда имя параметра метода экземпляра совпадает с именем свойства экземпляра. В этой ситуации имя параметра имеет приоритет и появляется необходимость ссылаться на свойство в более подходящей форме. Вы используете свойство self для того, чтобы увидеть различие между именем параметра и именем свойства.

Здесь self разграничивает параметр метода x и свойство экземпляра, которое тоже x:

struct Point {
    var x = 0.0, y = 0.0
    func isToTheRightOf(x: Double) -> Bool {
        return self.x > x
    }
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
    print("Эта точка находится справа от линии, где x == 1.0")
}
// Выведет "Эта точка находится справа от линии, где x == 1.0"

Без префикса self, Swift будет думать, что в обоих случаях x будет как раз параметром метода, который так же называется x.

Изменение типов значений методами экземпляра

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

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

Вы можете все это осуществить, если поставите ключевое слово mutating перед словом func для определения метода:

struct Point {
   var x = 0.0, y = 0.0
   mutating func moveBy(x deltaX: Double, y deltaY: Double) {
      x += deltaX
      y += deltaY
   }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("Сейчас эта точка на (\(somePoint.x), \(somePoint.y))")
// Выведет "Сейчас эта точка на (3.0, 4.0)"

Структура Point определяет метод moveBy(x:y:), который передвигает точку типа Point на определенное количество значений. Вместо того, чтобы вернуть новую точку, этот метод фактически изменяет координаты точки, которая его вызвала. Ключевое слово mutating добавлено к определению метода, для того, чтобы изменить значения свойств.

Обратите внимание, что вы не можете вызвать изменяющийся (mutating) метод для константных типов структуры, потому как ее свойства не могут быть изменены, даже если свойства являются переменными, что описано в главе “Хранимые свойства экземпляров структуры”

let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveBy(x: 2.0, y: 3.0)
// это вызовет сообщение об ошибке

Присваивание значения для self внутри изменяющегося метода

Изменяющиеся методы могут присваивать полностью новый экземпляр неявному свойству self. Пример Point, приведенный выше, мог бы быть записан в такой форме:

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        self = Point(x: x + deltaX, y: y + deltaY)
    }
}

Такая версия изменяющегося метода moveBy(x:y:) создает абсолютно новую структуру, чьим значениям x, y присвоены значения конечной точки. Конечный результат вызова этой альтернативной версии метода будет абсолютно таким же как и в ранней версии.

Изменяющиеся методы для перечислений могут установить отдельный член перечисления как неявный параметр self:

enum TriStateSwitch {
    case off, low, high
    mutating func next() {
        switch self {
        case .off:
            self = .low
        case .low:
            self = .high
        case .high:
            self = .off
        }
    }
}
var ovenLight = TriStateSwitch.low
ovenLight.next()
// ovenLight равен .high
ovenLight.next()
// ovenLight равен .off

В этом примере мы рассматриваем перечисление с тремя положениями переключателя. Переключатель проходит последовательно три положения (off, low, high), каждый раз меняя положение, как вызывается метод next().

 

Swift: 
4.0