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

Объявления

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

Объявление вводит новое имя или конструкцию в вашу программу. Например, вы используете объявления, вводя функции и методы, переменные и константы, а также определяя новые именованные перечисления, структуры, классы и типы протоколов. Вы можете также использовать объявления для расширения поведения существующего именованного типа и импортирования символов, объявленным в другом месте, в вашу программу.

В Swift большинство объявлений являются также определениями, в том смысле, что они реализуются или инициализируются в то же время, когда и объявляются. Тем не менее, поскольку протоколы не реализуют свои члены (элементы), большинство членов протокола являются только объявлениями. Так как различие не столь важно в Swift, а также для простого удобства, термин “объявления” используются и для объявлений и для определений.

Грамматика объявления

declaration → import-declaration­
declaration → constant-declaration­
declaration → variable-declaration­
declaration → typealias-declaration­
declaration → function-declaration­
declaration → enum-declaration­
declaration → struct-declaration­
declaration → class-declaration­
declaration → protocol-declaration­
declaration → initializer-declaration­
declaration → deinitializer-declaration­
declaration → extension-declaration­
declaration → subscript-declaration­
declaration → operator-declaration­
declarations → declaration­declarations­ opt­

Код верхнего уровня

Код верхнего уровня в исходном файле Swift состоит из нуля или более инструкций, объявлений и выражений. По умолчанию, переменные, константы и другие именованные объявления, объявленные на верхнем уровне исходного файла, доступны для использования в каждом исходном файле, который является частью того же самого модуля. Вы можете переопределить такое поведение по умолчанию, установив объявление с доступом изменения уровня, как описано в разделе Уровни доступа.

Грамматика объявления верхнего уровня

top-level-declaration statements­ opt­

Блоки кода

Блок кода используется различными объявлениями и контролирующими структурами для объединения объявлений. Выглядит следующим образом:

{
      инструкции
}

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

Грамматика блока кода

code-block {­ statements­ opt­ 

Объявление импорта

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

import модуль

Устанавливая более детальные ограничения импортированных символов, вы можете задать конкретный подмодуль или конкретное объявление в пределах модуля или подмодуля. Когда используется эта детальная форма, только импортируемый символ (а не модуль, который его объявляет) становится доступным в текущей области.

import тип импорта модуль . имя символа
import модуль . подмодуль

Грамматика объявления импорта

import-declaration attributes­ opt ­import­ import-kind­opt ­import-path­
import-kind typealias­ | struct­ | class­ | enum­ | protocol­ | var­ | func­
import-path import-path-identifier­ | import-path-identifier­ .­ import-path­
import-path-identifier identifier­ | operator­

Объявления константы

Объявления константы вводят в вашу программу именованное значение константы. Объявления константы объявляются с помощью ключевого слова let и выглядят следующим образом:

let имя константы: тип = выражение

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

Если константа объявлена ​​в глобальной области видимости, она должна быть инициализирована со значением. Когда объявление константы происходит в контексте описания класса или структуры, то это объявление считается постоянным свойством. Объявления константы это не вычисляемые свойства и, следовательно, не будет геттеров или сеттеров.

Если имя константы в объявлении константы является шаблоном кортежа, имя каждого элемента в кортеже привязано к соответствующему значению в выражении инициализатора.

let (firstNumber, secondNumber) = (10, 42)

В этом примере firstNumber - это именованная константа для значения 10, а secondNumber - это именованная константа для значения 42. Обе константы теперь можно использовать независимо друг от друга:

print("Первое число равно \(firstNumber).")

// Выведет "Первое число равно 10."

print("Второе число равно \(secondNumber).")

// Выведет "Второе число равно 42."

Тип аннотаций (: type) опционален в объявлении константы, когда тип имени константы можно вывести, как описано в разделе Вывод типов.

Чтобы объявить свойство типа константы, отметьте объявление модификатором объявления static. Свойства типа обсуждаются в Вывод типов.

Для получения дополнительной информации о константах и их использования, см. Константы и переменные и Свойства хранения.

Грамматика объявления константы

constant-declaration attributes­ opt­ declaration-modifiers­ opt ­let ­pattern-initializer-list­
pattern-initializer-list pattern-initializer­ pattern-initializer­ ,­ pattern-initializer-list­
pattern-initializer pattern­ initializer­ opt­
initializer =­ expression­

Объявление переменных

Объявление переменной вводит в вашу программу именованное значение переменной и объявляется с помощью ключевого слова var.

Объявление переменных имеет несколько форм, объявляющих различные виды именованных, изменяемых значений, в том числе переменные хранения и вычисляемые переменные, а так же переменные свойства хранения, наблюдатели свойств, статические свойства переменных. Соответствующая форма зависит от области, в которой объявляется переменная, ​​и типа переменной, которую вы собираетесь объявить.

Заметка

Вы можете также объявлять свойства в контексте объявления протокола, как описано в "Объявлении свойств протокола".

Вы можете переопределить свойство в подклассе, отметив объявление свойства подкласса модификатором объявления override, как описано в Переопределение.

Переменные хранения и переменные свойства хранения

Следующая форма объявляет переменные хранения или переменные свойств хранения:

var имя переменной: тип = выражение

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

Выражение инициализатора не может быть прописано в протоколе, а во всех других контекстах выражение инициализатора является опциональным. Тем не менее, если нет ни одного выражения инициализатора, то объявление переменной должно содержать явную аннотацию типа (: type).

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

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

Вычисляемые переменные и Вычисляемые свойства

Следующая форма объявляет вычисляемую переменную или вычисляемое свойство:

var имя переменной: тип {
    get {
        инструкции
    }
    set(имя сеттера) {
        инструкции
    }
}

Вы задаете эту форму объявления переменной в глобальной области, локальной области функции, или в контексте объявления класса или структуры, перечисления. Если объявление переменной этой формы объявляется в глобальной области или локальной области видимости функции, оно рассматривается как вычисляемая переменная. Когда оно объявляется в контексте объявления класса или структуры или расширения, то рассматривается как вычисляемое свойство.

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

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

В отличие от именованного значения хранения и переменных свойств хранения, значение вычисляемого им именованного значения или вычисляемого свойства не сохраняются в памяти.

Для получения дополнительной информации см. Вычисляемые свойства.

Наблюдатели переменной хранения и наблюдатели свойств

Кроме того, вы можете объявить переменную хранения или свойство с наблюдателями willSet и didSet. Переменная хранения или свойство, объявленные с наблюдателями выглядят так:

var имя переменной: тип = выражение {
    willSet(имя сеттера) {
       инструкции
    }
    didSet(имя сеттера) {
       инструкции
    }
}

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

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

Выражение инициализатора опционально в контексте объявления класса или структуры, но обязательно в других местах. Тип аннотации опционален, если тип может быть выведен из выражения инициализатора.

Наблюдатели willSet и didSet предоставляют возможность наблюдать (и реагировать соответствующим образом), когда устанавливается значение переменной или свойства. Наблюдатели не вызываются, когда переменная или свойство инициализируются впервые. Вместо этого они вызываются только тогда, когда значение устанавливается вне контекста инициализации.

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

Имя сеттера и круглые скобки в условиях willSet и didSet являются опциональными. Если вы предоставляете имена сеттеров, они используются в качестве имен параметров наблюдателей willSet и didSet. Если вы не предоставляете имена сеттеров, дефолтное имя параметра наблюдателя willSet будет newValue и дефолтное имя параметра наблюдателя didSet будет oldValue.

Условие didSet является дефолтным, когда вы предоставляете условие willSet. Аналогичным образом, условие willSet является опциональным, если вы предоставляете условие didSet.

Для получения дополнительной информации см. Наблюдатели свойств.

Переменные свойства типа

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

Заметка

В объявлении класса ключевое слово static имеет тот же эффект, что и отметка обоими модификаторами объявления class и final.

Грамматика объявления переменной

variable-declaration variable-declaration-head­ pattern-initializer-list­
variable-declaration variable-declaration-head­ variable-name­ type-annotation­ code-block­
variable-declaration variable-declaration-head­ variable-name­ type-annotation­ getter-setter-block­
variable-declaration variable-declaration-head­ variable-name ­type-annotation­ getter-setter-keyword-block­
variable-declaration variable-declaration-head­ variable-name­ initializer­ willSet-didSet-block­
variable-declaration variable-declaration-head ­variable-name­ type-annotation­ initializer­opt­ willSet-didSet-block­
variable-declaration-head attributes­ opt­ declaration-modifiers­opt­ var­
variable-name identifier­
getter-setter-block code-block­
getter-setter-block {­ getter-clause­ setter-clause­opt­ 
getter-setter-block {­ setter-clause­ getter-clause­ 
getter-clause attributes­opt­ get­ code-block­
setter-clause attributes­opt­ set­ setter-name­opt­ code-block­
setter-name (­ identifier­ 
getter-setter-keyword-block {­ getter-keyword-clause ­setter-keyword-clause­opt­ 
getter-setter-keyword-block {­ setter-keyword-clause­ getter-keyword-clause­ 
getter-keyword-clause attributes­opt­ get­
setter-keyword-clause attributes­opt ­set­
willSet-didSet-block {­ willSet-clause­ didSet-clause­opt­ 
willSet-didSet-block {­ didSet-clause­ willSet-clause­opt­ 
willSet-clause attributes­opt­ willSet­ setter-name­opt­ code-block­
didSet-clause attributes­opt­ didSet­ setter-name­opt­ code-block­

Объявление псевдонима типа

Объявление псевдонима типа вводит именованный псевдоним существующего типа в программу. Объявления псевдонима типа объявляются с помощью ключевого слова typealias и имеют следующий вид:

typealias имя = существующий тип

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

Объявление псевдонима типа может использовать универсальные параметры для того, чтобы давать имена существующим типам. Например:

typealias StringDictionary<T> = Dictionary<String, T>

// Эти словари имеют один и тот же тип.
var dictionary1: StringDictionary<Int> = [:]
var dictionary2: Dictionary<String, Int> = [:]

Когда псевдоним типа объявлен с универсальными параметрами, то ограничения этих параметров должны точно совпадать с ограничениями параметров существующего типа. Например:

typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>

Так как псевдоним и основной тип взаимозаменяемы, то псевдоним не может добавлять другие универсальные параметры.

Внутри объявления протокла псевдоним типа может дать более короткое, более удобное имя часто используемому типу. Например:

protocol Sequence {
    associatedtype Iterator: IteratorProtocol
    typealias Element = Iterator.Element
}
 
func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
    // ...
}

Без этого псевдонима, метод sum должен был бы ссылать на ассоциативный тип T.Iterator.Element, вместо T.Element.

Подробнее см. Объявление ассоциированного типа протокола.

Грамматика объявления псевдонима типа

typealias-declaration attributes­opt­ access-level-modifier­opt­ typealias­ typealias-name­ typealias-assignment­
typealias-name identifier­

typealias-assignment = ­type­

Объявление функции

Объявление функции вводит функцию или метод в вашу программу. Функция, объявленная ​​в контексте класса, структуры, перечисления, или протокола, называется методом. Объявления функций осуществляются с помощью ключевого слова func и имеют следующий вид:

func имя функции (параметры) -> возвращаемый тип {
    инструкции
}

Если функция имеет возвращаемый тип Void, возвращаемый тип может быть опущен следующим образом:

func имя функции (параметры) {
    инструкции
}

Тип каждого параметра должен быть включен, так как он не может быть выведен. Хотя параметры функции являются по умолчанию константами, вы можете написать let перед именем параметра, чтобы подчеркнуть его поведение. Если написать перед именем параметра inout, параметр может быть изменен в области видимости функции. Параметры In-Out подробно обсуждаются в "Сквозные параметры", ниже.

Функции могут возвращать несколько значений, используя тип кортежа как тип возвращаемого значения функции.

Определение функции может появиться внутри другого объявления функции. Этот вид функции известен как вложенная функция. Подробнее см. Вложенные функции.

Имена параметров

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

имя параметра: тип параметра

Параметр имеет локальное имя, которое используется в теле функции, а также внешнее имя, которое используется в качестве ярлыка для аргумента при вызове метода. По умолчанию имена параметров также используются как ярлыки аргументов. Например:

func f(x: Int, y: Int) -> Int { return x + y }

f(x: 1, y: 2) // и x, и у имеют свой ярлык

Вы можете переопределить дефолтное поведение для лейблов аргументов, используя одну из форм:

ярлык аргумента имя параметра: тип параметра
_ имя параметра: тип параметра

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

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

func repeatGreeting(_ greeting: String, count n: Int) { /* Поприветствовать n раз */ }

repeatGreeting("Hello, world!", count: 2) //  count имеет ярлык, а greeting нет

Сквозные параметры

Сквозные параметры передаются следующим образом:

  1. Когда вызывается функция, значение аргумента копируется.
  2. В теле функции копия изменяется.
  3. Когда функция возвращается, значение копии присваивается исходному аргументу.

Такое поведение известно как “copy-in copy-out”  или вызов по результату значения. Например, когда вычисляемое свойство или свойство с наблюдателями передается в качестве сквозного параметра, его геттер вызывается как часть вызова функции и его сеттер вызывается как часть возврата функции.

В качестве оптимизации, когда аргумент является значением, хранящимся в физическом адресе памяти, то же место в памяти используется как внутри, так и вне тела функции. Оптимизированное поведение известно как вызов по ссылке. Оно удовлетворяет всем требованиям модели копирования copy-in copy-out в то время как происходит удаление излишек копирования. Напишите свой код, используя модель, данную copy-in copy-out, вне зависимости от оптимизации вызова по ссылке, так чтобы он правильно вел себя с или без оптимизации. 

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

Вы не можете передавать один и тот же аргумент многочисленным сквозным параметрам, потому что порядок, в котором записываются обратно копии не определен, что означает, что окончательное значение оригинала также не может быть определено. Например:

var x = 10
func f(a: inout Int, b: inout Int) {
    a += 1
    b += 10
}
f(a: &x, b: &x) // ошибка

Замыкание или вложенная функция, которая захватывает сквозной параметр должна быть не сбегающей (@nonescaping). Если вам нужно захватить сквозной параметр без изменения его значения или для того, чтобы отслеживать изменения значения другим кодом, используйте список захвата, чтобы явно захватить параметр.

func someFunction(a: inout Int) -> () -> Int {
    return { [a] in return a + 1 }
}

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

func multithreadedFunction(queue: DispatchQueue, x: inout Int) {
    // Сделайте локальную копию и скопируйте ее обратно.
    var localX = x
    defer { x = localX }
    
    // Работайте с localX асинхронно, затем дождитесь возврата.
    queue.async { someMutatingOperation(&localX) }
    queue.sync {}
}

Подробнее см. Сквозные параметры.

Особые виды параметров

Параметры могут быть проигнорированы, принимают переменное число значений, а также обеспечивают дефолтные значения, используя следующие формы:

_ : тип параметра
имя параметра: тип параметра...
имя параметра: тип параметра = дефолтное значение аргумента

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

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

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

func f(x: Int = 42) -> Int { return x }
f()       // Корректно, использует дефолтное значение
f(x: 7)   // Корректно, использует предоставленное значение
f(7)      // Некорректно, отсутствует ярлык аргумента

Специальные виды методов

Методы перечисления или структуры, которые изменяют self, должны быть отмечены модификатором объявления mutating.

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

Методы, связанные с типом, а не с экземпляром типа, должны быть отмечены модификатором объявления static для перечислений и структур или модификатором объявления class для классов.

Генерирующие функции и методы

Функции и методы, которые могут генерировать ошибку, должны быть отмечены ключевым словом throws. Эти функции и методы известны, как генерирующие ошибку функции и методы. Выглядят они вот так:

func имя функции (парметры) throws -> возвращаемый тип {
    инструкции
}

Вызовы генерирующей ошибки функции или метода должны быть завернуты в выражение try или try! (то есть, в области оператора try и try!).

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

Вы не можете перегрузжать функцию, основываясь только на том, может ли функция генерировать ошибку. Тем не менее, вы можете перегрузить функцию, основываясь на том, может ли параметр функции генерировтаь ошибку.

Генерирующий метод не может переопределить негенерирующий метод, и генерирующий метод не может удовлетворить требование протокола для негенерирующего метода. Тем не менее, негенерирующий метод может переопределить генерирующий метод, и негенерирующий метод может удовлетворить требование генерирующего протокола.

Повторно генерирующие функции и методы

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

func someFunction(callback: () throws -> Void) rethrows {
    try callback()
}

Повторно генерирующая функция или метод могут содержать оператор throw только внутри условия catch. Это позволяет вызывать генерирующую функцию внутри блока do-catch и обрабатывать ошибки в условии catch, генерируюя другую ошибку. В дополнение, условие catch должно обрабатывать только ошибки, сгенерированные одним из генерирующих параметров повторно генерирующей функции. Например,следующий код будет неправильным, потому что уловие catch будет обрабатывать ошибку, сгенерированную alwaysThrows().

func alwaysThrows() throws {
    throw SomeError.error
}

func someFunction(callback: () throws -> Void) rethrows {
   do {
      try callback()
      try alwaysThrows()  // ошибка, так как alwaysThrows не является генерирующим параметром
   } catch {
      throw AnotherError.error
   }
}

Генерирующий метод не может переопределить повторно генерирующий метод, и генерирующий метод не может удовлетворить требование протокола для повторно генерирующего метода. Тем не менее, повторно генерирующий метод может переопределить генерирующий метод, и повторно генерирующий метод может удовлетворить требование протокола для генерирующего метода.

Функции, не возвращающие значения

Swift определяет тип Never, который является индикатором того, что функция не возвращает результата. Функции и методы с возвращаемым типом Never называются невозвращающими. Невозвращающие функции и методы либо являются источниками непоправимых ошибок, либо является источником начала работ, которые продолжаются до бесконечности. Это все значит, что код, который должен исполнятся сразу после вызова, никогда отработан не будет. Генерирующие и генерирующие повторно функции могут перебросить выполнение программы в соответствующий catch блок, даже если они являются невозвращающими. Невозвращающие функции или методы могут быть вызваны для звершения работы else скобки инструкции guard.

Вы можете переопределить невозвращающий метод, но новый метод должен сохранить возвращаемый тип и поведение не возврата.

Грамматика объявления функции

function-declaration → function-head function-name generic-parameter-clause­opt­ function-signature function-body­opt­ 
‌function-head → attributes­opt­ declaration-modifiers­opt­ func
‌function-name → identifier | operator
‌function-signature → parameter-clause throws­opt­ function-result­opt­ 
‌function-signature → parameter-clause rethrows function-result­opt­ 
‌function-result →  -> attributes­opt­ type
‌function-body → code-block
‌parameter-clause → () | ( parameter-list )
‌parameter-list → parameter | parameter parameter-list
‌parameter → external-parameter-name­opt­ local-parameter-name type-annotation default-argument-clause­opt­ 

parameter → external-parameter-name­opt­ local-parameter-name type-annotation
‌parameter → external-parameter-name­opt­ local-parameter-namet ype-annotation ...
‌external-parameter-name → identifier
‌local-parameter-name → identifier
‌default-argument-clause → = expression

Объявление перечисления

Объявление перечисления вводит именованный тип перечисления в вашу программу.

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

Типы перечислений могут принимать любое количество протоколов, но не могут наследовать от классов, структур или других перечислений.

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

Как и структуры, но в отличие от классов, перечисления - это типы значений. Экземпляры перечисления копируются при присваивании переменным или константам, или при передаче в качестве аргументов вызова функции. Для получения дополнительной информации о типах значений см. Структуры и перечисления являются типами значений.

Вы можете расширить поведение типа перечисления через объявление расширения, подробнее "Объявление расширений", ниже.

Перечисления с кейсами любого типа

Следующая форма объявляет тип перечисления, содержащий кейсы перечисления любого типа:

enum имя перечисления: принятые протоколы {
    case кейс перечисления 1
    case кейс перечисления 2 (связанные значения типа)
}

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

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

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

enum Number {
   case integer(Int)
   case real(Double)
}
let f = Number.integer
// f является функцией типа (Int) -> Number
 
// Применяем функцию f для создания массива экземпляров Number с целочисленными значениями
let evenInts: [Number] = [0, 2, 4, 6].map(f)

Для получения дополнительной информации см. Связанные значения.

Индиректные перечисления

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

Чтобы включить индиректность для конкретного кейса перечисления, отметьте его модификатором объявления indirect.

enum Tree<T> {
    case empty
    indirect case node(value: T, left: Tree, right: Tree)

}

Чтобы включить индиректность для всех кейсов перечисления, отметьте полностью все перечисление модификатором indirect - это удобно, когда перечисление содержит много кейсов, и каждый должен быть отмечен модификатором indirect.

Кейс перечисления, отмеченный модификатором indirect, должен иметь связное значение. Перечисление, отмеченное модификатором indirect может содержать смесь кейсов, имеющих связные значения и кейсы, не имеющие их. Тем не менее, он не может содержать каких-либо кейсов, также отмеченных модификатором indirect.

Перечисления с кейсами типа исходного значения

Следующая форма объявляет тип перечисления, который содержит кейсы перечисления одного и того же базового типа:

enum имя перечисления: исходное значение типа, принятые протоколы {
    case кейс перечисления 1 = исходное значение 1
    case кейс перечисления 2 = исходное значение 2
}

В этой форме каждый конкретный блок кейса состоит из ключевого слова case, за которым следует один или более кейсов перечисления через запятую. В отличие от кейсов в первой форме, здесь каждый кейс имеет основное значение, называемое исходное значение того же базового типа. Тип этих значений задается в типе исходных значений и должен представлять интеджер, число с плавающей точкой, строку или символ. В частности, тип исходного значения должен соответствовать протоколу Equatable и одному из следующих  протоколов: IntegerLiteralConvertible для целочисленных литералов, FloatingPointLiteralConvertible для литералов с плавающей точкой, StringLiteralConvertible для строковых литералов, которые содержат любое количество символов, и ExtendedGraphemeClusterLiteralConvertible для строковых литералов, которые содержат только один символ. Каждый кейс должен иметь уникальное имя и быть присвоен уникальному исходному значению.

Если исходное значение установлено как Int и вы не присваиваете явно значение кейсам, они неявно присваиваются значениям 0, 1, 2, и так далее. Каждый неуказанный кейс типа Int неявно присваивается исходному значению, которое автоматически увеличивается от исходного значения предыдущего кейса.

enum ExampleEnum: Int {
   case a, b, c = 5, d
}

В приведенном выше примере, исходное значение ExampleEnum. A равно 0 и значение ExampleEnum.B равно 1. Так как значение ExampleEnum.C явно установлено на 5, то значение ExampleEnum.D автоматически увеличивается с 5 и будет 6.

Если тип исходного значения установлен как String, и не присваиваете явно значения кейсам, каждому кейсу без значения будет неявно присвоена строка с тем же текстом, что и имя этого кейса.

enum GamePlayMode: String {
   case cooperative, individual, competitive
}

В приведенном выше примере, исходным значением GamePlayMode.cooperative является "cooperative", исходным значением GamePlayMode.individual является "individual", исходным значением GamePlayMode.competitive является "competitive".

Перечисления, которые имеют кейсы типа исходного значения, неявно соответствуют протоколу RawRepresentable, определенному в стандартной библиотеке Swift. В результате, у них есть свойство rawValue и проваливающийся инициализатор с подписью init?(rawValue: RawValue). Вы можете также использовать свойство rawValue для доступа к исходному значению кейса перечисления, как в ExampleEnum.B.rawValue. Вы можете также использовать исходное значение для того, чтобы найти соответствующий кейс, если таковой имеется, вызвав проваливающийся инициализатор перечисления, как в ExampleEnum(rawValue: 5), который возвращает опциональный кейс. Подробнее см. Исходные значения.

Доступ к кейсам перечисления

Для того, чтобы сослаться на кейс типа перечисления, используйте точку (.), как в EnumerationType.EnumerationCase. Когда тип перечисления можно вывести из контекста, вы можете опустить его (точка по-прежнему требуется). Тип перечисления - шаблонный, а шаблоны кейсов перечисления  находятся в блоках кейсов оператора switch.

Грамматика объявления перечислений

enum-declaration attributes­opt­ access-level-modifier­opt­ union-style-enum­
enum-declaration attributes­opt­ access-level-modifier­opt­ raw-value-style-enum­
union-style-enum indirect­opt­ enum­ enum-name­ generic-parameter-clause­opt­ type-inheritance-clause­opt­ {­ union-style-enum-members­opt­ 
union-style-enum-members union-style-enum-member­ union-style-enum-members­opt­
union-style-enum-member declaration­ | union-style-enum-case-clause­
union-style-enum-case-clause attributes­opt­ indirect­opt­ case­ union-style-enum-case-list­
union-style-enum-case-list union-style-enum-case­ | union-style-enum-case­ , ­union-style-enum-case-list­
union-style-enum-case enum-case-name­ tuple-type­opt­
enum-name identifier­
enum-case-name identifier­
raw-value-style-enum enum­ enum-name­ generic-parameter-clause­opt­ type-inheritance-clause­ {­ raw-value-style-enum-members ­
raw-value-style-enum-members raw-value-style-enum-member­ raw-value-style-enum-members­opt­
raw-value-style-enum-member declaration­ raw-value-style-enum-case-clause­
raw-value-style-enum-case-clause attributes­opt­ case­ raw-value-style-enum-case-list­
raw-value-style-enum-case-list raw-value-style-enum-case­ | raw-value-style-enum-case ­,­ raw-value-style-enum-case-list­ 
raw-value-style-enum-case enum-case-name­ raw-value-assignment­opt­
raw-value-assignment =­ raw-value-literal­
raw-value-literal numeric-literal­ | static-string-literal­ | boolean-literal­

Объявление структуры

Объявление структуры вводит именованный тип структуры в вашу программу. Объявление структуры объявляются с помощью ключевого слова struct и выглядит следующим образом:

struct имя структуры: принятые протоколы {
    объявления
}

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

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

Есть три способа создания экземпляра ранее объявленной структуры:

  • Вызовите один из инициализаторов, объявленных внутри структуры, как описано в Инициализаторы
  • Если нет ни одного объявленного инициализатора, вызовите почленный инициализатор структуры, подробнее см. Почленные инициализаторы для структурных типов
  • Если нет ни одного объявленного инициализатора, и всем свойствам объявления структуры были даны начальные значения, вызовите дефолтный инициализатор структуры, как описано в Дефолтные инициализаторы
  • Процесс инициализации объявленных свойств структуры см. Инициализация.

Свойства экземпляра структуры можно получить через синтаксис: точка (.), как описано в разделе Доступ к свойствам.

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

Вы можете расширить поведение типа структур с объявлением расширения.

Грамматика объявления структур

struct-declaration → attributes­opt ­access-level-modifier­opt­ struct­ - struct-name­  generic-parameter-clause­opt­  type-inheritance-clause­opt­  generic-where-clause­opt ­struct-body­
struct-name → identifier­
struct-body → {­ struct-members­opt­ 
struct-members → struct-member­struct-members­opt­
struct-member → declaration­  |  compiler-control-statement­

Объявление класса

Объявление класса вводит именованный классовый тип в вашу программу. Объявления класса объявляются с помощью ключевого слова class и выглядят следующим образом:

class имя класса: имя суперкласса, принятые протоколы {
    объявления
}

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

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

Как говорится в "Объявление инициализатора", классы могут иметь назначеные (designated) и пригодные (convenience ) инициализаторы. Назначенный инициализатор класса должен инициализировать все объявленные свойства класса и он должен сделать это до вызова любого из назначенных инициализаторов своего суперкласса.

Класс может переопределить свойства, методы, сабскрипты и инициализаторы своего суперкласса. Переопределенные свойства, методы, сабскрипты, и назначенные инициализаторы должны быть отмечены модификатором объявления override.

Для того, чтобы подклассы реализовывали инициализатор суперкласса, отметьте инициализатор суперкласса модификатором объявления required. Реализация подкласса этого инициализатора также должна быть отмечена модификатором объявления required.

Хотя свойства и методы, объявленные в суперклассе, наследуются текущим классом, назначенные инициализаторы, объявленные в суперклассе, так не наследуются. Тем не менее, если текущий класс перекрывает все назначенные инициализаторы суперкласса, он наследует вспомогательные инициализаторы суперкласса. Классы в Swift не наследуют от универсального базового класса.

Есть два способа создания экземпляра ранее заявленного класса:

  • Вызов один из инициализаторов, объявленных внутри класса, как описано в Инициализаторы
  • Если нет ни одного объявленного инициализатора, и всем свойствам объявления класса были даны начальные значения, вызовите дефолтный инициализатор класса, как описано в Дефолтные инициализаторы

Получите доступ к свойствам экземпляра класса через синтаксис: точка (.), как описано в Доступ к свойствам.

Классы являются ссылочными типами. Экземпляры класса на них ссылаются, а не копируются, когда присвоены переменным или константам, или при передаче в качестве аргументов вызова функции. Подробнее см. Структуры и перечисления - типы значения.

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

Грамматика объявления класса

class-declaration → attributes­opt­  access-level-modifier­opt­  final­opt­  class­ class-name­  generic-parameter-clause­opt  ­type-inheritance-clause­opt­  generic-where-clause­opt­  class-body­
class-declaration → attributes­opt­  final­ access-level-modifier­opt  ­class­ class-name­  generic-parameter-clause­opt  ­type-inheritance-clause­opt­  generic-where-clause­opt­  class-body­
class-name → identifier­
class-body → {­ class-members­opt­ 
class-members → class-member  ­class-members­opt­
class-member → declaration­  |  compiler-control-statement­

Объявление протокола

Объявление протокола вводит именованный тип протокола в вашу программу. Объявления протокола объявляются в глобальной области видимости с помощью ключевого слова protocol и выглядят следующим образом:

protocol имя протокола: наследуемые протоколы {
    объявление членов протокола
}

Тело протокола содержит от ноля и более объявлений членов протокола, которые описывают требования соответствия, которые должны выполнять любые типы, принимающие протокол. В частности, протокол может объявлять, что соответствующие типы должны реализовывать определенные свойства, методы, инициализаторы, и сабскрипты. Протоколы могут также объявлять специальные виды псевдонимов типа, называемые связные типы, которые могут указывать отношения между различными объявлениями протокола. Объявление протокола не может содержать класс, структуру, перечисление, или другие объявления протокола. Объявления членов протокола будет подробно обсуждаться далее.

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

Заметка

Вы также можете объединить требования соответствия нескольких протоколов, используя типы композиций протокола, как описано в Тип композиции протоколов и Композиция протоколов.

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

По умолчанию, типы, соответствующие протоколу, должны реализовывать все свойства, методы и сабскрипты, объявленные в протоколе. Тем не менее, вы можете отметить эти объявления членов протокола модификатором объявления optional, чтобы указать, что их реализация по типу соответствия требованиям является опциональной. Модификатор optional может быть применен только к членам, отмеченным атрибутом objc и только к членам протоколов, отмеченных атрибутом objc. В результате, только классовые типы могут принимать и соответствовать протоколу, который содержит требования опциональных членов. Для получения дополнительных сведений о том, как использовать модификатор объявления optional и получить доступ к опциональным членам протокола, например, когда вы не уверены, реализует ли их соответствующий требованиям тип см. Опциональные требования протокола.

Для того, чтобы ограничить принятие протокола только до классовых типов, отметьте протокол с требованием class, написав ключевое слово class в качестве первого элемента в списке наследуемых протоколов после двоеточия. Например, следующий протокол может быть принят только по классовым типам:

protocol SomeProtocol: class {
    /* Члены протокола */
}

Любой протокол, который наследует от протокола, отмеченного требованием class, также может быть принят только по классовым типам.

Заметка

Если протокол отмечен атрибутом objc, требование class неявно применяется к этому протоколу. Нет никакой необходимости отмечать протокол требованием class явно.

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

Вы можете использовать протоколы для объявления того, какие методы делегат класса или структуры должен реализовывать, как описано в Делегирование.

Грамматика объявления протокола

protocol-declaration → attributes­opt­ access-level-modifier­opt­ protocol­ protocol-name­ type-inheritance-clause­opt­ protocol-body­
protocol-name → identifier­
protocol-body →  protocol-member-declarations­opt­ 
protocol-member-declaration → protocol-property-declaration­
protocol-member-declaration → protocol-method-declaration­
protocol-member-declaration → protocol-initializer-declaration­
protocol-member-declaration → protocol-subscript-declaration­
protocol-member-declaration → protocol-associated-type-declaration­
protocol-member-declarations → protocol-member-declaration­ protocol-member-declarations­opt­

Объявление свойств протокола

Протоколы объявляют, что соответствующие типы должны реализовывать свойство, включая объявление свойства протокола в тело объявления протокола. Объявления свойств протокола имеют специальную форму объявления переменной:

var имя свойства: тип { get set }

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

Требования геттера и сеттера могут быть удовлетворены соответствующим типом различными способами. Если объявление свойства включает ключевые слова get и set, то соответствующий тип может реализовать его через переменную свойств хранения или вычисляемое свойство, одновременно удобные для чтения и записи (то есть то, которое реализует как геттер, так и сеттер). Однако объявление свойства не может быть реализовано в виде свойства константы или вычисляемого свойства,  доступного только для чтения. Если объявление свойства включает в себя только ключевое слово get, оно может быть реализовано как любой вид свойства. Подробнее Требование свойств.

Грамматика объявления свойств протокола

protocol-property-declaration → variable-declaration-head­  variable-name  ­type-annotation  ­getter-setter-keyword-block­

Объявление методов протокола

Протоколы объявляют, что соответствующие типы должны реализовывать метод, включая объявление метода протокола в тело объявления протокола. Объявления методов протокола имеют тот же вид, что и объявления функций, с двумя исключениями: они не включают в себя тело функции, и вы не можете предоставить какие-либо дефолтные значения параметров как часть объявления функции. Примеры соответствующих типов, реализующих требования метода протокола, можно найти в Требования свойств.

Для объявления класса или требования статического метода в объявлении протокола, отметьте объявление метода модификатором объявления static. Классы, реализующие этот метод, объявляют метод модификатором class. Структуры, реализующие его, должны вместо этого объявлять метод модификатором объявления static. Если вы реализуете метод в расширении, используйте модификатор class, если вы расширяете класс, и модификатор static, если вы расширяете структуру.

Грамматика объявления метода протокола

protocol-method-declaration → function-head  ­function-name  ­generic-parameter-clause­opt   ­function-signature­

Объявление инициализатора протокол

Протоколы объявляют, что соответствующие им типы должны реализовывать инициализатор, включая объявление инициализатора протокола в тело объявления протокола. Объявления инициализатора протокола имеют ту же форму, что и объявления инициализатора, за исключением того, что они не включают в себя тело инициализатора.

Соответствующий тип может удовлетворить требование непроваливающегося инициализатора протокола через реализацию непроваливающегося инициализатора или проваливающегося инициализатора init!. Соответствующий тип может удовлетворить требование проваливающегося инициализатора протокола через реализацию инициализатора любого вида.

Когда класс реализует инициализатор для удовлетворения требований инициализатора протокола, то инициализатор должен быть отмечен модификатором объявления required, если класс уже не был ранее отмечен модификатором объявления final.

Грамматика объявления инициализатора протокола

protocol-initializer-declaration → initializer-head­  generic-parameter-clause­opt ­ parameter-clause ­throws­opt­
protocol-initializer-declaration → initializer-head  ­generic-parameter-clause­opt ­ parameter-clause­ rethrows­

Объявление сабскрипта протокола

Протоколы объявляют, что соответствующие типы должны реализовывать сабскрипт, включая объявление сабскрипта протокола в тело объявления протокола. У объявления сабскрипта протокола есть специальная форма: 

subscript (парметры) -> возвращаемый тип { get set }

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

Грамматика объявления сабскрипта протокола

protocol-subscript-declaration → subscript-head ­subscript-result­ getter-setter-keyword-block­

Объявление ассоциированного типа протокола

Протоколы объявляют ассоциированные типы, используя ключевое слово associatedtype. Ассоциированный тип обеспечивает псевдоним для типа, который используется в качестве части объявления протокола. Ассоциированные типы аналогичны параметрам типа в общем положении параметров, но они связаны с Self в протоколе, в котором они объявлены. В этом контексте, Self относится к возможному типу, соответствующему протоколу. Подробнее Связанные типы.

Грамматика объявления ассоциированного типа

protocol-associated-type-declaration → attributes­opt­ access-level-modifier­opt­ associatedtype­ typealias-name­ type-inheritance-clause­opt­ typealias-assignment­opt­

Объявление инициализатора

Объявления инициализатора вводит в вашу программу инициализатор для классов, структур или перечислений. Объявления инициализатора объявляются с помощью ключевого слова init и имеют две основные формы.

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

Следующая форма объявляет инициализаторы для структур, перечислений и назначенных инициализаторов классов:

init(параметры) {
    инструкции
}

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

Назначенные инициализаторы могут быть объявлены только в контексте объявления класса, и, следовательно, не могут быть добавлены к классу через объявление расширения.

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

Для того, чтобы объявить вспомогательные инициализаторы для класса, отметьте объявление инициализатора модификатором объявления convenience.

convenience init(параметры) {
    инструкции
}

Вспомогательные инициализаторы могут делегировать процесс инициализации другому вспомогательному инициализатору или одному из назначенных инициализаторов класса. Тем не менее, процессы инициализации должны заканчиваться вызовом назначенного инициализатора, что в конечном счете инициализирует свойства класса. Вспомогательные инициализаторы не могут вызывать инициализаторы суперкласса.

Вы можете отметить назначенные и вспомогательные инициализаторы необходимым модификатором объявления required, чтобы каждый подкласс реализовывал инициализатор. Реализация подкласса этого инициализатора также должна быть отмечена модификатором объявления required.

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

Как и с методами, свойствами и сабскриптами, вам необходимо отметить переопределенные назначенные инициализаторы модификатором объявления override.

Заметка

Если вы отмечаете инициализатор модификатором объявления required, вам не нужно отмечать инициализатор модификатором override, когда вы переопределяете требуемый инициализатор в подклассе.

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

Чтобы увидеть примеры инициализатора в различных объявлений типа см. Инициализация.

Проваливающиеся инициализаторы

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

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

struct SomeStruct {
    let property: String
    // создает опциональный экземпляр структуры'SomeStruct'
    init?(input: String) {
        if input.isEmpty {
            // избавляемся от 'self' и возвращаем 'nil'
            return nil
        }
        property = input
    }
}

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

if let actualInstance = SomeStruct(input: "Hello") {
    // что-то делаем с экземпляром структуры 'SomeStruct'
} else {
    // инциализация структуры 'SomeStruct' провалилась и инициализатор вернул 'nil'
}

Проваливающийсяинициализатор может возвращать nil в любой момент реализации тела инициализатора.

Проваливающийся инициализатор может делегировать любым видам инициализаторов. Непроваливающийся инициализатор может делегировать другому непроваливающемуся инициализатору или проваливающемуся инициализатору init!. Непроваливающийся инициализатор может делегировать проваливающемуся инициализатору init? через принудительное извлечение результата инициализатора, например через написание super.init()!.

Неудачная инициализация распространяется через делегирование инициализатора. В частности, если проваливающийся инициализатор делегирует инициализатору, который падает и возвращает nil, то инициализатор, который делегировал, также падает и неявно возвращает nil. Если непроваливающийся инициализатор делегирует проваливающемуся инициализатору init!, который падает и возвращает nil, то возникает ошибка выполнения (как если бы вы использовали оператор ! для извлечения опционала со значением nil).

Проваливающийся назначенный инициализатор может быть переопределен в подклассе любым видом назначенного инициализатора. Непроваливающийся назначенный инициализатор может быть переопределен в подклассе только непроваливающимся назначенным инициализатором.

Подробнее см. Проваливающиеся инициализаторы.

Грамматика объявления инициализатора

initializer-declaration → initializer-head­ generic-parameter-clause­opt­ parameter-clause­ throws­opt ­initializer-body­
initializer-declaration → initializer-head­ generic-parameter-clause­opt­ parameter-clause­ rethrows­ initializer-body­
initializer-head → attributes­opt­ declaration-modifiers­opt­ init­
initializer-head → attributes­opt­ declaration-modifiers­opt­ init­?­
initializer-head → attributes­opt­ declaration-modifiers­opt­ init­!­
initializer-body → code-block­

Объявление деинициализатора

Объявление деинициализатора объявляет деинициализатор для типа класса. Деинициализаторы не принимают никаких параметров и имеют следующий вид:

deinit {
    инструкции
}

Деинициализатор вызывается автоматически, когда больше нет ссылок на объект класса, непосредственно перед тем, как объект класса освобождается. Деинициализатор может быть объявлен только в теле объявления класса, а не в расширении класса - и каждый класс может иметь не более одного деинициализатора.

Подкласс наследует деинициализатор суперкласса, который неявно вызывается непосредственно перед тем, как объект класса освобождается. Объект подкласса не освобождается, пока все деинициализаторы в цепочке наследования не закончат выполнение.

Деинициализаторы не вызываются напрямую.

Подробнее Деинициализация.

Грамматика объявления деинициализатора

deinitializer-declaration → attributes­opt­ deinit­ code-block­

Объявление расширения

Объявление расширения позволяет расширять поведение существующих типов класса, структур и перечислений. Объявления расширений объявляются с помощью ключевого слова extension и имеют следующий вид:

extension имя типа: принятые протоколы {
    объявления
}

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

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

Свойства, методы и инициализаторы существующего типа не могут быть переопределены в расширении этого типа.

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

Грамматика объявления расширений

extension-declaration → attributes­opt­  access-level-modifier­opt­  extension­ type-identifier  ­type-inheritance-clause­opt  ­extension-body­
extension-declaration → attributes­opt  ­access-level-modifier­opt­  extension ­type-identifier­  generic-where-clause  ­extension-body­
extension-body → {­ extension-members­opt­ 
extension-members → extension-member­  extension-members­opt­
extension-member → declaration­  compiler-control-statement­

Объявления санскрита

Объявления сабскрипта позволяет вам добавлять поддержку сабскрипта для объектов определенного типа и, как правило, используются для обеспечения удобным синтаксисом доступа к элементам в коллекции, списке или последовательности. Сабскрипты объявляются с помощью ключевого слова subscript и имеют следующий вид:

subscript (парметры) -> возвращаемый тип {
    get {
        инструкции
    }
    set(имя сеттера) {
        инструкции
    }
}

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

Параметры определяют один или несколько индексов, используемых для доступа к элементам соответствующего типа в индексном выражении (например, i в выражении object[i]). Хотя индексы, используемые для доступа к элементам, могут быть любого типа, каждый параметр должен содержать аннотацию типа, чтобы указать тип каждого индекса. Возвращаемый тип определяет тип элемента, к которому осуществляется доступ.

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

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

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

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

Вы также можете объявить сабскрипты в контексте объявления протокола.

Для получения дополнительной информации о сабскриптах см. Индексы.

Грамматика объявления сабскрипта

subscript-declaration → subscript-head­ subscript-result­ code-block­
subscript-declaration → subscript-head ­subscript-result­ getter-setter-block­
subscript-declaration → subscript-head­ subscript-result­getter-setter-keyword-block­
subscript-head → attributes­opt­ declaration-modifiers­opt­ subscript­ parameter-clause­
subscript-result → ->­attributes­opt­ type­

Объявление оператора

Объявление оператора вводит новый инфиксный, префиксный или постфиксный оператор в вашу программу и объявляется с помощью ключевого слова operator.

Вы можете объявить операторов трех различных вариантов: инфиксных, префиксных и постфиксных. Вариант положения оператора определяется положением оператора по отношению к своим операндам.

Существуют три основные формы объявления оператора, по одной для каждого варианта положения. Вариант положения оператора определяется через отметку объявления оператора модификатором объявления infix, prefix, или postfix перед ключевым словом operator. В каждой форме название оператора может содержать только символы оператора, определенные в Операторы.

Следующая форма объявляет новый инфиксный оператор:

infix operator имя оператора : группа приоритета

Инфиксный оператор - это бинарный оператор, который записывается между двумя операндами, например распространенное дополнение оператора (+) в выражении 1 + 2.

Инфиксные операторы могут дополнительно указывать группу приоритета. Если вы пропускаете указание группы приоритета при создании оператора, то Swift использует дефектную группу - DefaultPrecedence, которая определена более высоким приоритетом, чем TernaryPrecedence

Следующая форма объявляет новый префиксный оператор:

prefix operator имя оператора {}

Префиксный оператор - это унарный оператор, который записывается непосредственно перед его операндом, например, префикс логического оператора NOT (!) В выражении !a.

Объявление префиксных операторов не указывает уровень приоритета. Префиксные операторы неассоциативны.

Следующая форма объявляет новый постфиксный оператор:

postfix operator имя оператора {}

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

Как и в случае с префиксными оператораторами, объявление постфиксных операторов не определяет уровень приоритета. Постфиксные операторы являются неассоциативными.

После объявления нового оператора, вы реализуете его, объявляя функцию, имеющую то же имя, что и оператор. Если вы реализуете префиксный или постфиксный оператор, то вам необходимо также отметить это объявление функции модификатором объявления prefix или postfix. Если вы реализуете инфиксный оператор, то вы не отмечаете объявление функции модификатором объявления infix. Подробнее Пользовательские операторы.

Грамматика объявления оператора

operator-declaration → prefix-operator-declaration­ | postfix-operator-declaration­ infix-operator-declaration­
prefix-operator-declaration → prefix­ operator ­operator­
postfix-operator-declaration → postfix­ operator­ operator­
infix-operator-declaration → infix­ operator ­operator­ ­infix-operator-attributes­opt­ 
infix-operator-group → :­ precedence-group-name­

Объвление групп приоритета

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

Объявления групп приоритета имеет следующую форму:

precedencegroup имя группы приоритета
    higherThan: имя нижней группы
    lowerThan: имя верхней группы
associativity: ассоциативность
assignment: присваивание

Списки имен нижней и верхней групп определяют отношение новой группы приоритета к уже существующим группам. Атрибут группы приоритета lowerThan может быть использован только для ссылки на другие группы приоритета, которые объявлены за пределами текущего модуля. Когда два оператора соревнуются между собой за свои операнды, как например, в случае 2 + 3 * 5, побеждает оператор, который более тесно связан со своими операндами.

Заметка

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

Swift определяет множество групп приоритета для использования вместе с операторами определенных в стандартной библиотеке Swift. Например операторы сложения (+) и вычитания (-) принадлежат к группе AdditionPrecedence, а операторы умножения (*) и деления (/) принадлежат группе MultiplicationPrecedence. Для полного списка групп приоритета предоставляемых стандартной библиотекой Swift смотрите Swift Standard Library Operators Reference.

Ассоциативность оператора определяет как последовательность операторов с одним и тем же уровнем приоритета группируются вместе в случае отсутствия группирующих круглых скобок. Ассоциативность определяется одним из регистрозависимых ключевых слов left, right, none. Если вы пропускаете ассоциативность, то она по умолчанию устанавливается как none. Операторы, которые имеют левую ассоциативность работают слева на право. Например, оператор вычитания (-) является левоассоциативным, так что выражение 4 - 5 - 6 группируется как (4 - 5) - 6 и вычисляется как -7. Операторы, которые имеют правую ассоциативность, работают справа на лево. Операторы, которые имеют ассоциативность none, не ассоциируются. Операторы с ассоциативностью none не могут располагаться рядом друг с другом. Например, оператор < имеет ассоциативность none, что значит 1 < 2 < 3 не является корректным выражением.

Assignment в группе приоритета определяет приоритет оператора, когда он используется в операции, где имеет место быть опциональная цепочка. Когда assignment имеет значение true, то оператор соответствующей группы приоритета использует те же правила внутри опциональной цепочки, что и операторы присваивания из стандартной библиотеки. В противном случае, когда assignment имеет значение false, операторы из группы приоритета следуют тем же правилам опциональной цепочки, что и операторы не выполняющие присваивания.

Грамматика объявления групп приоритета

recedence-group-declaration → precedencegroup­ precedence-group-name­ {­ precedence-group-attributes­ opt­ 
precedence-group-attributes → precedence-group-attribute ­precedence-group-attributes­ opt­
precedence-group-attribute → precedence-group-relation­
precedence-group-attribute → precedence-group-assignment­
precedence-group-attribute → precedence-group-associativity­
precedence-group-relation → higherThan­  precedence-group-names­
precedence-group-relation → lowerThan­ : ­precedence-group-names­
precedence-group-assignment → assignment­  boolean-literal­
precedence-group-associativity → associativity­ :­ left­
precedence-group-associativity → associativity­ :­ right­
precedence-group-associativity → associativity­ : ­none­
precedence-group-names → precedence-group-name­  |  precedence-group-name­precedence-group-names­
precedence-group-name → identifier­

Модификаторы объявления

Модификаторы объявления - это ключевые слова или контекстно-зависимые ключевые слова, которые изменяют поведение или значение объявления. Вы указываете модификатор объявления через написание соответствующего ключевого слова или контекстно-зависимого ключевого слова между атрибутами объявления (если таковые имеются) и ключевым словом, которое вводит объявление.

dynamic

Примените этот модификатор к любому члену класса, который может быть представлен Objective-C. Когда вы отмечаете объявление члена модификатором dynamic, доступ к этому члену всегда динамически отправляется во время выполнения Objective-C. Доступ к этому члену никогда не встраивается или девиртуализуется компилятором.

Поскольку объявления, отмеченные модификатором dynamic, отправляются во время выполнения Objective-C, они неявно отмечаются атрибутом objc.

final

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

lazy

Примените этот модификатор к переменной свойства хранения класса или структуры, чтобы указать, что начальное значение свойства вычисляется и хранится не более одного раза, с момента, когда к свойству первоначально обратились. В качестве примера того, как использовать модификатор lazy, см. Ленивые свойства хранения.

optional

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

Вы можете применить модификатор optional только к протоколам, которые отмечены атрибутом objc. В результате, только типы классов могут принимать и соответствовать протоколу, который содержит требования опциональных членов. Для получения дополнительных сведений о том, как использовать модификатор optional и более подробной информации см. Опциональные требования протоколов.

required

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

unowned

Применяйте этот модификатор к переменным хранения, константам или к свойствам хранения для отображения того, что переменная или свойство имеют бесхозную ссылку на объект, который является их значением. Если вы попытаетесь получить доступ к переменной или свойству после того, как объект быть освобожден, то приложение выдаст ошибку исполнения. Как и в случае со слабыми ссылками, тип свойства или значения должен быть классовым. В отличии от типов объектов слабых ссылок, объекты с бесхозными ссылками не могут быть опциональными. Для более подробной информации об unowned ссылках читайте в Бесхозные ссылки.

unowned(safe)

Явное указание unowned

unowned(unsafe)

Применяйте этот модификатор к переменным хранения, константам или к свойствам хранения для отображения того, что переменная или свойство имеют бесхозную ссылку на объект, который является их значением. Если вы попытаетесь получить доступ к переменной или свойству после того, как объект быть освобожден, то вы получите доступ к памяти, где ранее находился объект, что является не безопасной для памяти операцией. В отличии от типов объектов слабых ссылок, объекты с бесхозными ссылками не могут быть опциональными. Для более подробной информации об unowned ссылках читайте в Бесхозные ссылки.

weak

Модификатор weak применяется к переменной или переменной свойства хранения, чтобы указать, что переменная или свойство имеет слабую ссылку на объект, хранящийся в качестве его значения. Тип переменной или свойства должен быть опциональным типом класса. Используйте модификатор weak, чтобы избежать сильных ссылочных циклов. Подробнее Weak ссылки.

Уровни контроля доступа

Swift обеспечивает три уровня доступа: public, internal и private. Вы можете отметить объявление одним из модификаторов доступа, описанные ниже, чтобы указать уровень доступа объявления. Контроль доступа подробно обсуждается в Уровни доступа.

open

Примените этот модификатор к объявлению, чтобы указать, что к объявлению можно получить доступ через код в том же модуле, где находится само объявление. К объявлениям, отмеченным модификатором уровня доступа open, можно также получить доступ, а так же наследоваться через код в модуле, который импотритует модуль, содержащий это объявление.

public

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

internal

Примените этот модификатор к объявлению, чтобы указать, что доступ к объявлению может быть только через код в том же модуле, что и объявление. По умолчанию, большинство объявлений неявно отмечены модификатором уровня доступа internal.

fileprivate

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

private

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

Каждый модификатор уровня доступа, описанный выше, опционально принимает один аргумент, который состоит из ключевого слова set в круглых скобках (например, private(set)). Используйте эту форму модификатора уровня доступа, если вы хотите указать уровень доступа для сеттера переменной или сабскрипта, что меньше или равно уровню доступа переменной или самого сабскрипта, что подробно описано в Геттеры и сеттеры.

Грамматика объявления модификатора

declaration-modifier → class­ convenience­ dynamic­ final­ infix­ lazy­ optional­ override­ postfix­ prefix­ required­ static­ unowned­ unowned­safe­ | unowned­unsafe­ | weak­
declaration-modifier → access-level-modifier­
declaration-modifier → mutation-modifier­
declaration-modifiers → declaration-modifier­declaration-modifiers­opt­
access-level-modifier → private­  private­set­)­
access-level-modifier → fileprivate­ fileprivate­set­
access-level-modifier → internal­ internal­set­
access-level-modifier → public­ public­set­
access-level-modifier → open­ open­set­
mutation-modifier → mutating­ nonmutating­

Swift: 
3.0