Spec-Zone .ru
спецификации, руководства, описания, API

Библиотека разработчика XCode

Разработчик

Swift язык программирования

iBook
На этой странице

Инициализация

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

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

Экземпляры типов классов могут также реализовать deinitializer, выполняющий любую пользовательскую очистку непосредственно перед тем, как освобожден экземпляр того класса. Для получения дополнительной информации о deinitializers, посмотрите Deinitialization.

Установка начальных значений для сохраненных свойств

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

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

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

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

  • init() {
  • // perform some initialization here
  • }

Пример ниже определяет новую вызванную структуру Fahrenheit сохранить температуры, выраженные в Шкале Фаренгейта. Fahrenheit структура имеет сохраненное свойство того, temperature, который имеет тип Double:

  • struct Fahrenheit {
  • var temperature: Double
  • init() {
  • temperature = 32.0
  • }
  • }
  • var f = Fahrenheit()
  • println("The default temperature is \(f.temperature)° Fahrenheit")
  • // prints "The default temperature is 32.0° Fahrenheit"

Структура определяет единственный инициализатор, init, без параметров, который инициализирует сохраненную температуру со значением 32.0 (точка замерзания воды, когда выражено в Шкале Фаренгейта).

Значения свойств по умолчанию

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

Можно записать Fahrenheit структурируйте сверху в более простой форме путем обеспечения значения по умолчанию для temperature свойство в точке, которой объявляется свойство:

  • struct Fahrenheit {
  • var temperature = 32.0
  • }

Настройка инициализации

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

Параметры инициализации

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

Следующий пример определяет вызванную структуру Celsius, который хранит температуры, выраженные в Шкале Цельсия. Celsius структура реализует два пользовательских вызванные инициализатора init(fromFahrenheit:) и init(fromKelvin:), которые инициализируют новый экземпляр структуры со значением от различной шкалы температур:

  • struct Celsius {
  • var temperatureInCelsius: Double
  • init(fromFahrenheit fahrenheit: Double) {
  • temperatureInCelsius = (fahrenheit - 32.0) / 1.8
  • }
  • init(fromKelvin kelvin: Double) {
  • temperatureInCelsius = kelvin - 273.15
  • }
  • }
  • let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
  • // boilingPointOfWater.temperatureInCelsius is 100.0
  • let freezingPointOfWater = Celsius(fromKelvin: 273.15)
  • // freezingPointOfWater.temperatureInCelsius is 0.0

Первый инициализатор имеет единственный параметр инициализации с внешним именем fromFahrenheit и локальное имя fahrenheit. Второй инициализатор имеет единственный параметр инициализации с внешним именем fromKelvin и локальное имя kelvin. Оба инициализатора преобразовывают свой отдельный аргумент в значение в Шкале Цельсия и хранят это значение в вызванном свойстве temperatureInCelsius.

Локальные и внешние названия параметра

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

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

Следующий пример определяет вызванную структуру Color, с тремя постоянными вызванными свойствами red, green, и blue. Эти свойства хранят значение между 0.0 и 1.0 указать сумму красного, зеленого цвета, и синий в цвете.

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

  • struct Color {
  • let red, green, blue: Double
  • init(red: Double, green: Double, blue: Double) {
  • self.red = red
  • self.green = green
  • self.blue = blue
  • }
  • init(white: Double) {
  • red = white
  • green = white
  • blue = white
  • }
  • }

Оба инициализатора могут использоваться для создания нового Color экземпляр, путем обеспечения назвал значения для каждого параметра инициализатора:

  • let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
  • let halfGray = Color(white: 0.5)

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

  • let veryGreen = Color(0.0, 1.0, 0.0)
  • // this reports a compile-time error - external names are required

Параметры инициализатора без внешних имен

Если Вы не хотите использовать внешнее имя для параметра инициализатора, запишите подчеркивание (_) вместо явного внешнего имени для того параметра для переопределения поведения по умолчанию.

Вот расширенная версия Celsius пример от ранее, с дополнительным инициализатором для создания нового Celsius экземпляр от a Double значение, которое уже находится в Шкале Цельсия:

  • struct Celsius {
  • var temperatureInCelsius: Double
  • init(fromFahrenheit fahrenheit: Double) {
  • temperatureInCelsius = (fahrenheit - 32.0) / 1.8
  • }
  • init(fromKelvin kelvin: Double) {
  • temperatureInCelsius = kelvin - 273.15
  • }
  • init(_ celsius: Double) {
  • temperatureInCelsius = celsius
  • }
  • }
  • let bodyTemperature = Celsius(37.0)
  • // bodyTemperature.temperatureInCelsius is 37.0

Вызов инициализатора Celsius(37.0) ясно в его намерении без потребности во внешнем названии параметра. Является поэтому надлежащим записать этот инициализатор как init(_ celsius: Double) так, чтобы это можно было вызвать путем обеспечения ня назван Double значение.

Дополнительные типы свойства

Если Ваш пользовательский тип имеет сохраненное свойство, которому логически позволяют не иметь “никакого значения” — возможно, потому что его значение не может быть установлено во время инициализации, или потому что позволяется не иметь “никакого значения” в некоторой более поздней точке — объявляют свойство с дополнительным типом. Свойства дополнительного типа автоматически инициализируются со значением nil, указание, что свойство сознательно предназначается еще, чтобы не иметь “никакого значения” во время инициализации.

Следующий пример определяет вызванный класс SurveyQuestion, с дополнительным String свойство вызывают response:

  • class SurveyQuestion {
  • var text: String
  • var response: String?
  • init(text: String) {
  • self.text = text
  • }
  • func ask() {
  • println(text)
  • }
  • }
  • let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
  • cheeseQuestion.ask()
  • // prints "Do you like cheese?"
  • cheeseQuestion.response = "Yes, I do like cheese."

Ответ на вопрос об исследовании не может быть известен, пока его не спрашивают, и таким образом, response свойство объявляется с типом String?, или “дополнительный String”. Это автоматически присваивается значение по умолчанию nil, значение “никакой строки все же”, когда новый экземпляр SurveyQuestion инициализируется.

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

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

Можно пересмотреть SurveyQuestion пример сверху для использования постоянного свойства, а не переменного свойства для text свойство вопроса, чтобы указать, что вопрос не изменяется один раз экземпляр SurveyQuestion создается. Даже при том, что text свойство является теперь константой, оно может все еще быть установлено в инициализаторе класса:

  • class SurveyQuestion {
  • let text: String
  • var response: String?
  • init(text: String) {
  • self.text = text
  • }
  • func ask() {
  • println(text)
  • }
  • }
  • let beetsQuestion = SurveyQuestion(text: "How about beets?")
  • beetsQuestion.ask()
  • // prints "How about beets?"
  • beetsQuestion.response = "I also like beets. (But not with cheese.)"

Инициализаторы по умолчанию

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

Этот пример определяет вызванный класс ShoppingListItem, который инкапсулирует имя, количество и состояние закупки элемента в списке покупок:

  • class ShoppingListItem {
  • var name: String?
  • var quantity = 1
  • var purchased = false
  • }
  • var item = ShoppingListItem()

Поскольку все свойства ShoppingListItem класс имеет значения по умолчанию, и потому что это - базовый класс без суперкласса, ShoppingListItem автоматически получает реализацию инициализатора по умолчанию, создающую новый экземпляр со всем его набором свойств к их значениям по умолчанию. ( name свойство является дополнительным String свойство, и таким образом, это автоматически получает значение по умолчанию nil, даже при том, что это значение не записано в коде.) Пример выше использует инициализатор по умолчанию для ShoppingListItem класс для создания нового экземпляра класса с синтаксисом инициализатора, записанным как ShoppingListItem(), и присваивает этот новый экземпляр вызванной переменной item.

Инициализаторы Memberwise для типов структуры

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

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

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

Size структура автоматически получает init(width:height:) инициализатор memberwise, который можно использовать для инициализации нового Size экземпляр:

  • struct Size {
  • var width = 0.0, height = 0.0
  • }
  • let twoByTwo = Size(width: 2.0, height: 2.0)

Делегация инициализатора к типам значения

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

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

Для типов значения Вы используете self.init для обращения к другим инициализаторам от того же значения вводят при записи собственных инициализаторов. Можно только вызвать self.init из инициализатора.

Обратите внимание на то, что при определении пользовательского инициализатора для типа значения у Вас больше не будет доступа к инициализатору по умолчанию (или memberwise инициализатор, если это будет структура) для того типа. Это ограничение предотвращает ситуацию, в которой дополнительная существенная установка, предоставленная в более сложном инициализаторе, обходится кем-то случайно использование одного из автоматических инициализаторов вместо этого.

Следующий пример определяет пользовательское Rect структура для представления геометрического прямоугольника. Пример требует двух вызванных опорных конструкций Size и Point, оба из которых обеспечивают значения по умолчанию 0.0 для всех их свойств:

  • struct Size {
  • var width = 0.0, height = 0.0
  • }
  • struct Point {
  • var x = 0.0, y = 0.0
  • }

Можно инициализировать Rect структура ниже одним из трех способов — при помощи ее инициализированного нулем значения по умолчанию origin и size значения свойств, путем обеспечения определенной точки источника и размера, или путем обеспечения определенной центральной точки и размера. Эти опции инициализации представлены тремя пользовательскими инициализаторами, которые являются частью Rect определение структуры:

  • struct Rect {
  • var origin = Point()
  • var size = Size()
  • init() {}
  • init(origin: Point, size: Size) {
  • self.origin = origin
  • self.size = size
  • }
  • init(center: Point, size: Size) {
  • let originX = center.x - (size.width / 2)
  • let originY = center.y - (size.height / 2)
  • self.init(origin: Point(x: originX, y: originY), size: size)
  • }
  • }

Первое Rect инициализатор, init(), функционально то же как инициализатор по умолчанию, который получила бы структура, если это не имело своих собственных инициализаторов. Этот инициализатор имеет пустую организацию, представленную пустой парой изогнутых фигурных скобок {}, и не выполняет инициализации. Вызов этого инициализатора возвращает a Rect экземпляр, чей origin и size свойства оба инициализируются со значениями по умолчанию Point(x: 0.0, y: 0.0) и Size(width: 0.0, height: 0.0) из их определений свойства:

  • let basicRect = Rect()
  • // basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0)

Второе Rect инициализатор, init(origin:size:), функционально то же как memberwise инициализатор, который получила бы структура, если это не имело своих собственных инициализаторов. Этот инициализатор просто присваивается origin и size значения аргументов к надлежащим сохраненным свойствам:

  • let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
  • size: Size(width: 5.0, height: 5.0))
  • // originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0)

Третье Rect инициализатор, init(center:size:), немного более сложно. Это запускается путем вычисления надлежащей точки источника на основе a center точка и a size значение. Это тогда вызывает (или делегаты) к init(origin:size:) инициализатор, хранящий новый источник и значения размера в надлежащих свойствах:

  • let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
  • size: Size(width: 3.0, height: 3.0))
  • // centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)

init(center:size:) инициализатор, возможно, присвоил новые значения origin и size к надлежащим свойствам самостоятельно. Однако это более удобно (и расчетная организация в намерении) для init(center:size:) инициализатор для использования в своих интересах существующего инициализатора, уже обеспечивающего точно ту функциональность.

Наследование классов и инициализация

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

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

Определяемые инициализаторы и инициализаторы удобства

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

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

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

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

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

Синтаксис для определяемого и инициализаторов удобства

Определяемые инициализаторы для классов записаны таким же образом как простые инициализаторы для типов значения:

  • init(parameters) {
  •     statements
  • }

Инициализаторы удобства записаны в том же стиле, но с convenience модификатор поместил перед init ключевое слово, разделенное пространством:

  • convenience init(parameters) {
  •     statements
  • }

Делегация инициализатора к типам классов

Для упрощения отношений между определяемым и инициализаторами удобства Swift применяет соблюдающий трех правил для вызовов делегации между инициализаторами:

Правило 1

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

Правило 2

Инициализатор удобства должен вызвать другой инициализатор от того же класса.

Правило 3

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

Простой способ помнить это:

  • Определяемые инициализаторы должны всегда делегировать.

  • Инициализаторы удобства должны всегда делегировать через.

Эти правила проиллюстрированы в числе ниже:

image: ../Art/initializerDelegation01_2x.png

Здесь, суперкласс имеет единственный определяемый инициализатор и два инициализатора удобства. Один инициализатор удобства вызывает другой инициализатор удобства, поочередно вызывающий единственный определяемый инициализатор. Это удовлетворяет правила 2 и 3 сверху. Суперкласс самостоятельно не имеет дальнейшего суперкласса, и таким образом, не применяется правило 1.

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

Число ниже шоу более сложная иерархия классов для четырех классов. Это иллюстрирует, как определяемые инициализаторы в этой иерархии действуют как точки «трубы» для инициализации класса, упрощая взаимосвязи среди классов в цепочке:

image: ../Art/initializerDelegation02_2x.png

Двухфазная инициализация

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

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

Компилятор Swift выполняет четыре полезных проверки безопасности, чтобы удостовериться, что двухфазная инициализация завершается без ошибки:

Проверка безопасности 1

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

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

Проверка безопасности 2

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

Проверка безопасности 3

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

Проверка безопасности 4

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

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

Вот то, как двухфазная инициализация теряет значение, на основе этих четырех проверок безопасности выше:

Фаза 1

  • Инициализатор определяемого или удобства вызывают на классе.

  • Память для нового экземпляра того класса выделяется. Память еще не инициализируется.

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

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

  • Это продолжает цепочку наследования классов, пока не достигнута вершина цепочки.

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

Фаза 2

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

  • Наконец, любые инициализаторы удобства в цепочке имеют опцию настроить экземпляр и работать с self.

Вот то, как фаза 1 ищет требование инициализации гипотетического подкласса и суперкласса:

image: ../Art/twoPhaseInitialization01_2x.png

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

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

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

Как только все свойства суперкласса имеют начальное значение, его память считают полностью инициализированной, и Фаза 1 завершена.

Вот то, как фаза 2 ищет тот же вызов инициализации:

image: ../Art/twoPhaseInitialization02_2x.png

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

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

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

Наследование инициализатора и переопределение

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

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

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

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

С другой стороны, если Вы пишете инициализатор подкласса, соответствующий инициализатор удобства суперкласса, тот инициализатор удобства суперкласса никогда не может вызывать непосредственно Ваш подкласс согласно правилам, описанным выше в Делегации Инициализатора к Типам классов. Поэтому Ваш подкласс (строго говоря) не обеспечивает переопределение инициализатора суперкласса. В результате Вы не пишете override модификатор при обеспечении соответствующей реализации инициализатора удобства суперкласса.

Пример ниже определяет вызванный базовый класс Vehicle. Этот базовый класс объявляет сохраненное вызванное свойство numberOfWheels, со значением по умолчанию Int значение 0. numberOfWheels свойство используется вычисленным вызванным свойством description создать a String описание характеристик механизма:

  • class Vehicle {
  • var numberOfWheels = 0
  • var description: String {
  • return "\(numberOfWheels) wheel(s)"
  • }
  • }

Vehicle класс обеспечивает значение по умолчанию для своего единственного сохраненного свойства и не обеспечивает пользовательских инициализаторов самого. В результате это автоматически получает инициализатор по умолчанию, как описано в Инициализаторах По умолчанию. Инициализатор по умолчанию (когда доступный) всегда является определяемым инициализатором для класса и может использоваться для создания нового Vehicle экземпляр с a numberOfWheels из 0:

  • let vehicle = Vehicle()
  • println("Vehicle: \(vehicle.description)")
  • // Vehicle: 0 wheel(s)

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

  • class Bicycle: Vehicle {
  • override init() {
  • super.init()
  • numberOfWheels = 2
  • }
  • }

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

init() инициализатор для Bicycle запускается путем вызова super.init(), который вызывает инициализатор по умолчанию для Bicycle суперкласс класса, Vehicle. Это гарантирует что numberOfWheels унаследованное свойство инициализируется Vehicle прежде Bicycle имеет возможность изменить свойство. После вызова super.init(), исходное значение numberOfWheels заменяется новым значением 2.

Если Вы создаете экземпляр Bicycle, можно вызвать его наследованный description вычисленное свойство, чтобы видеть, как numberOfWheels свойство было обновлено:

  • let bicycle = Bicycle()
  • println("Bicycle: \(bicycle.description)")
  • // Bicycle: 2 wheel(s)

Автоматическое наследование инициализатора

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

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

Правило 1

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

Правило 2

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

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

Определяемый и инициализаторы удобства в действии

Следующий пример показывает определяемые инициализаторы, инициализаторы удобства и автоматическое наследование инициализатора в действии. Этот пример определяет иерархию трех вызванных классов Food, RecipeIngredient, и ShoppingListItem, и демонстрирует, как взаимодействуют их инициализаторы.

Базовый класс в иерархии вызывают Food, который является простым классом для инкапсуляции имени пищевых продуктов. Food класс представляет сингл String свойство вызывают name и обеспечивает два инициализатора для создания Food экземпляры:

  • class Food {
  • var name: String
  • init(name: String) {
  • self.name = name
  • }
  • convenience init() {
  • self.init(name: "[Unnamed]")
  • }
  • }

Число ниже шоу цепочка инициализатора для Food класс:

image: ../Art/initializersExample01_2x.png

Классы не имеют значения по умолчанию memberwise инициализатором, и таким образом, Food класс обеспечивает определяемый инициализатор, берущий вызванный отдельный аргумент name. Этот инициализатор может использоваться для создания нового Food экземпляр с собственным именем:

  • let namedMeat = Food(name: "Bacon")
  • // namedMeat's name is "Bacon"

init(name: String) инициализатор от Food класс предоставлен как определяемый инициализатор, потому что он гарантирует что все сохраненные свойства нового Food экземпляр полностью инициализируется. Food класс не имеет суперкласса, и таким образом, init(name: String) инициализатор не должен вызывать super.init() завершать его инициализацию.

Food класс также обеспечивает инициализатор удобства, init(), без параметров. init() инициализатор обеспечивает имя заполнителя по умолчанию для новой еды путем делегирования через к Food класс init(name: String) с a name значение [Unnamed]:

  • let mysteryMeat = Food()
  • // mysteryMeat's name is "[Unnamed]"

Второй класс в иерархии является подклассом Food вызванный RecipeIngredient. RecipeIngredient класс моделирует компонент в рецепте кулинарии. Это представляет Int свойство вызывают quantity (в дополнение к name свойство это наследовалось от Food) и определяет два инициализатора для создания RecipeIngredient экземпляры:

  • class RecipeIngredient: Food {
  • var quantity: Int
  • init(name: String, quantity: Int) {
  • self.quantity = quantity
  • super.init(name: name)
  • }
  • override convenience init(name: String) {
  • self.init(name: name, quantity: 1)
  • }
  • }

Число ниже шоу цепочка инициализатора для RecipeIngredient класс:

image: ../Art/initializersExample02_2x.png

RecipeIngredient класс имеет единственный определяемый инициализатор, init(name: String, quantity: Int), который может использоваться для заполнения всех свойств нового RecipeIngredient экземпляр. Этот инициализатор запускается путем присвоения переданного quantity параметр quantity свойство, которое является единственным новым свойством, представленным RecipeIngredient. После выполнения так, инициализатор делегирует до init(name: String) инициализатор Food класс. Этот процесс удовлетворяет проверку безопасности 1 от Двухфазной Инициализации выше.

RecipeIngredient также определяет инициализатор удобства, init(name: String), который используется для создания a RecipeIngredient экземпляр по имени один. Этот инициализатор удобства принимает количество 1 для любого RecipeIngredient экземпляр, создающийся без явного количества. Определение этого инициализатора удобства делает RecipeIngredient экземпляры, более быстрые и более удобные для создания, и, избегают дублирования кода при создании нескольких единственных количеств RecipeIngredient экземпляры. Этот инициализатор удобства просто делегирует через к определяемому инициализатору класса, передающему в a quantity значение 1.

init(name: String) инициализатор удобства, предоставленный RecipeIngredient берет те же параметры в качестве init(name: String) определяемый инициализатор от Food. Поскольку этот инициализатор удобства переопределяет определяемый инициализатор от своего суперкласса, он должен быть отмечен с override модификатор (как описано в Наследовании Инициализатора и Переопределяющий).

Даже при том, что RecipeIngredient обеспечивает init(name: String) инициализатор как инициализатор удобства, RecipeIngredient тем не менее, обеспечил реализацию всех определяемых инициализаторов ее суперкласса. Поэтому RecipeIngredient автоматически наследовал все инициализаторы удобства его суперкласса также.

В этом примере, суперклассе для RecipeIngredient Food, который имеет единственный вызванный инициализатор удобства init(). Этот инициализатор поэтому наследован RecipeIngredient. Наследованная версия init() функции точно таким же образом как Food версия, за исключением того, что это делегирует к RecipeIngredient версия init(name: String) вместо Food версия.

Все три из этих инициализаторов могут использоваться для создания новый RecipeIngredient экземпляры:

  • let oneMysteryItem = RecipeIngredient()
  • let oneBacon = RecipeIngredient(name: "Bacon")
  • let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)

Третий и заключительный класс в иерархии является подклассом RecipeIngredient вызванный ShoppingListItem. ShoppingListItem класс моделирует компонент рецепта, как это появляется в списке покупок.

Каждый элемент в списке покупок начинается, как «не куплено». Представлять этот факт, ShoppingListItem представляет вызванное булево свойство purchased, со значением по умолчанию false. ShoppingListItem также добавляет вычисленный description свойство, предоставляющее текстовое описание a ShoppingListItem экземпляр:

  • class ShoppingListItem: RecipeIngredient {
  • var purchased = false
  • var description: String {
  • var output = "\(quantity) x \(name)"
  • output += purchased ? " ✔" : " ✘"
  • return output
  • }
  • }

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

Число ниже шоу полная цепочка инициализатора для всех трех классов:

image: ../Art/initializersExample03_2x.png

Можно использовать все три из наследованных инициализаторов для создания нового ShoppingListItem экземпляр:

  • var breakfastList = [
  • ShoppingListItem(),
  • ShoppingListItem(name: "Bacon"),
  • ShoppingListItem(name: "Eggs", quantity: 6),
  • ]
  • breakfastList[0].name = "Orange juice"
  • breakfastList[0].purchased = true
  • for item in breakfastList {
  • println(item.description)
  • }
  • // 1 x Orange juice ✔
  • // 1 x Bacon ✘
  • // 6 x Eggs ✘

Здесь, новый массив вызывают breakfastList создается из литерала массивов, содержащего три новых ShoppingListItem экземпляры. Тип массива выведен, чтобы быть [ShoppingListItem]. После того, как массив создается, имя ShoppingListItem в начале массива изменяется от "[Unnamed]" к "Orange juice" и это отмечено как купленный. Печать описания каждого элемента в массиве показывает, что их состояния по умолчанию были установлены как ожидалось.

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

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

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

failable инициализатор создает дополнительную ценность типа, который он инициализирует. Вы пишете return nil в failable инициализаторе для указания точки, в которой может быть инициирован отказ в инициализации.

Пример ниже определяет вызванную структуру Animal, с константой String свойство вызывают species. Animal структура также определяет failable инициализатор с помощью единственного вызванного параметра species. Этот инициализатор проверяет если species значение, переданное инициализатору, является пустой строкой. Если пустая строка найдена, отказ в инициализации инициирован. Иначе, species значение свойства установлено, и инициализация успешно выполняется:

  • struct Animal {
  • let species: String
  • init?(species: String) {
  • if species.isEmpty { return nil }
  • self.species = species
  • }
  • }

Можно использовать этот failable инициализатор, чтобы попытаться инициализировать новое Animal экземпляр и проверять, успешно выполнилась ли инициализация:

  • let someCreature = Animal(species: "Giraffe")
  • // someCreature is of type Animal?, not Animal
  • if let giraffe = someCreature {
  • println("An animal was initialized with a species of \(giraffe.species)")
  • }
  • // prints "An animal was initialized with a species of Giraffe"

Если Вы передаете значение пустой строки failable инициализатору species параметр, инициализатор инициировал отказ в инициализации:

  • let anonymousCreature = Animal(species: "")
  • // anonymousCreature is of type Animal?, not Animal
  • if anonymousCreature == nil {
  • println("The anonymous creature could not be initialized")
  • }
  • // prints "The anonymous creature could not be initialized"

Инициализаторы Failable для перечислений

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

Пример ниже определяет вызванное перечисление TemperatureUnit, с тремя возможными состояниями (Kelvin, Celsius, и Fahrenheit). failable инициализатор используется для нахождения соответствующего элемента перечисления для a Character значение, представляющее температурный символ:

  • enum TemperatureUnit {
  • case Kelvin, Celsius, Fahrenheit
  • init?(symbol: Character) {
  • switch symbol {
  • case "K":
  • self = .Kelvin
  • case "C":
  • self = .Celsius
  • case "F":
  • self = .Fahrenheit
  • default:
  • return nil
  • }
  • }
  • }

Если параметр не соответствует одно из этих состояний, можно использовать этот failable инициализатор, чтобы выбрать соответствующий элемент перечисления для трех возможных состояний и заставить инициализацию перестать работать:

  • let fahrenheitUnit = TemperatureUnit(symbol: "F")
  • if fahrenheitUnit != nil {
  • println("This is a defined temperature unit, so initialization succeeded.")
  • }
  • // prints "This is a defined temperature unit, so initialization succeeded."
  • let unknownUnit = TemperatureUnit(symbol: "X")
  • if unknownUnit == nil {
  • println("This is not a defined temperature unit, so initialization failed.")
  • }
  • // prints "This is not a defined temperature unit, so initialization failed."

Инициализаторы Failable для перечислений с необработанными значениями

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

Можно переписать TemperatureUnit пример сверху для использования необработанных значений типа Character и использовать в своих интересах init?(rawValue:) инициализатор:

  • enum TemperatureUnit: Character {
  • case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
  • }
  • let fahrenheitUnit = TemperatureUnit(rawValue: "F")
  • if fahrenheitUnit != nil {
  • println("This is a defined temperature unit, so initialization succeeded.")
  • }
  • // prints "This is a defined temperature unit, so initialization succeeded."
  • let unknownUnit = TemperatureUnit(rawValue: "X")
  • if unknownUnit == nil {
  • println("This is not a defined temperature unit, so initialization failed.")
  • }
  • // prints "This is not a defined temperature unit, so initialization failed."

Инициализаторы Failable для классов

failable инициализатор для типа значения (т.е. структура или перечисление) может инициировать отказ в инициализации в любой точке в ее реализации инициализатора. В Animal пример структуры выше, инициализатор инициировал отказ в инициализации в, очень запускаются его реализации, перед species свойство было установлено.

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

Пример ниже шоу, как можно использовать неявно развернутое дополнительное свойство для удовлетворения этого требования в failable инициализаторе класса:

  • class Product {
  • let name: String!
  • init?(name: String) {
  • self.name = name
  • if name.isEmpty { return nil }
  • }
  • }

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

Однако Product класс, не структура. Это означает это в отличие от этого Animal, любой failable инициализатор для Product класс должен обеспечить начальное значение для name свойство прежде, чем инициировать отказ в инициализации.

В примере выше, name свойство Product класс определяется как наличие неявно развернутого дополнительного строкового типа (String!). Поскольку это имеет дополнительный тип, это означает что name свойство имеет значение по умолчанию nil прежде чем это будет присвоено определенное значение во время инициализации. Это значение по умолчанию nil поочередно средние значения, что все свойства, представленные Product класс имеет допустимое начальное значение. В результате failable инициализатор для Product может инициировать отказ в инициализации в начале инициализатора, если он передается пустая строка, прежде, чем присвоить определенное значение name свойство в инициализаторе.

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

  • if let bowTie = Product(name: "bow tie") {
  • // no need to check if bowTie.name == nil
  • println("The product's name is \(bowTie.name)")
  • }
  • // prints "The product's name is bow tie"

Распространение отказа в инициализации

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

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

Пример ниже определяет подкласс Product вызванный CartItem. CartItem класс моделирует элемент в корзине онлайн-шоппинга. CartItem представляет сохраненное постоянное вызванное свойство quantity и гарантирует, что это свойство всегда имеет значение, по крайней мере, 1:

  • class CartItem: Product {
  • let quantity: Int!
  • init?(name: String, quantity: Int) {
  • self.quantity = quantity
  • super.init(name: name)
  • if quantity < 1 { return nil }
  • }
  • }

quantity свойство имеет неявно развернутый целый тип (Int!). Как с name свойство Product класс, это означает что quantity свойство имеет значение по умолчанию nil прежде чем это будет присвоено определенное значение во время инициализации.

failable инициализатор для CartItem запускается путем делегирования до init(name:) инициализатор от его суперкласса, Product. Это удовлетворяет требование, чтобы failable инициализатор всегда выполнял делегацию инициализатора прежде, чем инициировать отказ в инициализации.

Если инициализация суперкласса перестала работать из-за пустого name значение, весь процесс инициализации сразу перестал работать, и никакой дальнейший код инициализации не выполняется. Если инициализация суперкласса успешно выполняется, CartItem инициализатор проверяет это, он получил a quantity значение 1 или больше.

Если Вы создаете a CartItem экземпляр с непустым названием и количеством 1 или больше, инициализация успешно выполняется:

  • if let twoSocks = CartItem(name: "sock", quantity: 2) {
  • println("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
  • }
  • // prints "Item: sock, quantity: 2"

При попытке создать a CartItem экземпляр с a quantity значение 0, CartItem инициализатор заставляет инициализацию перестать работать:

  • if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
  • println("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")
  • } else {
  • println("Unable to initialize zero shirts")
  • }
  • // prints "Unable to initialize zero shirts"

Точно так же, при попытке создать a CartItem экземпляр с пустым name значение, суперкласс Product инициализатор заставляет инициализацию перестать работать:

  • if let oneUnnamed = CartItem(name: "", quantity: 1) {
  • println("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")
  • } else {
  • println("Unable to initialize one unnamed product")
  • }
  • // prints "Unable to initialize one unnamed product"

Переопределение инициализатора Failable

Можно переопределить суперкласс failable инициализатор в подклассе, точно так же, как любой другой инициализатор. Также можно переопределить суперкласс failable инициализатор с подклассом non-failable инициализатор. Это позволяет Вам определить подкласс, для которого не может перестать работать инициализация, даже при том, что инициализации суперкласса позволяют перестать работать.

Обратите внимание на то, что при переопределении failable инициализатора суперкласса с nonfailable инициализатором подкласса инициализатор подкласса не может делегировать до инициализатора суперкласса. nonfailable инициализатор никогда не может делегировать к failable инициализатору.

Пример ниже определяет вызванный класс Document. Этот класс моделирует документ, который может быть инициализирован с a name свойство, которое является или значением непустой строки или nil, но не может быть пустая строка:

  • class Document {
  • var name: String?
  • // this initializer creates a document with a nil name value
  • init() {}
  • // this initializer creates a document with a non-empty name value
  • init?(name: String) {
  • self.name = name
  • if name.isEmpty { return nil }
  • }
  • }

Следующий пример определяет подкласс Document вызванный AutomaticallyNamedDocument. AutomaticallyNamedDocument разделите на подклассы переопределяет оба из определяемых инициализаторов, представленных Document. Эти переопределения гарантируют что AutomaticallyNamedDocument экземпляр имеет начальную букву name значение "[Untitled]" если пустая строка передается, если экземпляр инициализируется без имени, или init(name:) инициализатор:

  • class AutomaticallyNamedDocument: Document {
  • override init() {
  • super.init()
  • self.name = "[Untitled]"
  • }
  • override init(name: String) {
  • super.init()
  • if name.isEmpty {
  • self.name = "[Untitled]"
  • } else {
  • self.name = name
  • }
  • }
  • }

AutomaticallyNamedDocument переопределяет его failable суперкласс init?(name:) инициализатор с nonfailable init(name:) инициализатор. Поскольку AutomaticallyNamedDocument справляется со случаем пустой строки по-другому, чем его суперкласс, его инициализатор не должен перестать работать, и таким образом, он обеспечивает nonfailable версию инициализатора вместо этого.

init! Инициализатор Failable

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

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

Требуемые инициализаторы

Запишите required модификатор перед определением инициализатора класса, чтобы указать, что каждый подкласс класса должен реализовать тот инициализатор:

  • class SomeClass {
  • required init() {
  • // initializer implementation goes here
  • }
  • }

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

  • class SomeSubclass: SomeClass {
  • required init() {
  • // subclass implementation of the required initializer goes here
  • }
  • }

Установка значения свойства по умолчанию с закрытием или функцией

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

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

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

  • class SomeClass {
  • let someProperty: SomeType = {
  • // create a default value for someProperty inside this closure
  • // someValue must be of the same type as SomeType
  • return someValue
  • }()
  • }

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

Пример ниже определяет вызванную структуру Checkerboard, который моделирует управление по игре Средств проверки (также известный как Наброски):

image: ../Art/checkersBoard_2x.png

В игру Средств проверки играют на десять десятью плата с чередованием черных и белых квадратов. Представлять эту игровую доску, Checkerboard структуре вызвали единственное свойство boardColors, который является массивом 100 Bool значения. Значение true в массиве представляет черный квадрат и значение false представляет белый квадрат. Первый элемент в массиве представляет верхний левый квадрат на плате, и последний элемент в массиве представляет нижний правый квадрат на плате.

boardColors массив инициализируется с закрытием для установки его значений цвета:

  • struct Checkerboard {
  • let boardColors: [Bool] = {
  • var temporaryBoard = [Bool]()
  • var isBlack = false
  • for i in 1...10 {
  • for j in 1...10 {
  • temporaryBoard.append(isBlack)
  • isBlack = !isBlack
  • }
  • isBlack = !isBlack
  • }
  • return temporaryBoard
  • }()
  • func squareIsBlackAtRow(row: Int, column: Int) -> Bool {
  • return boardColors[(row * 10) + column]
  • }
  • }

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

  • let board = Checkerboard()
  • println(board.squareIsBlackAtRow(0, column: 1))
  • // prints "true"
  • println(board.squareIsBlackAtRow(9, column: 9))
  • // prints "false"