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

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

Разработчик

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

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

Классы и структуры

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

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

Сравнение классов и структур

Классы и структуры в Swift имеют много общих черт. Оба могут:

  • Определите свойства для хранения значений

  • Определите методы для обеспечения функциональности

  • Определите нижние индексы для обеспечения доступа к их значениям с помощью нижнего синтаксиса

  • Определите инициализаторы для установки их начального состояния

  • Будьте расширены для расширения их функциональности вне реализации по умолчанию

  • Соответствуйте протоколам для обеспечения стандартной функциональности определенного вида

Для получения дополнительной информации посмотрите Свойства, Методы, Нижние индексы, Инициализацию, Расширения и Протоколы.

Классы имеют дополнительные возможности, которые не делают структуры:

  • Наследование позволяет одному классу наследовать характеристики другого.

  • Преобразование типа позволяет Вам проверить и интерпретировать тип экземпляра класса во время выполнения.

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

  • Подсчет ссылок позволяет больше чем одну ссылку на экземпляр класса.

Для получения дополнительной информации посмотрите Наследование, Преобразование типа, Deinitialization и Автоматический Подсчет ссылок.

Синтаксис определения

Классы и структуры имеют подобный синтаксис определения. Вы представляете классы с class ключевое слово и структуры с struct ключевое слово. Оба помещают их все определение в паре фигурных скобок:

  • class SomeClass {
  • // class definition goes here
  • }
  • struct SomeStructure {
  • // structure definition goes here
  • }

Вот пример определения структуры и определения класса:

  • struct Resolution {
  • var width = 0
  • var height = 0
  • }
  • class VideoMode {
  • var resolution = Resolution()
  • var interlaced = false
  • var frameRate = 0.0
  • var name: String?
  • }

Пример выше определяет новую вызванную структуру Resolution, описать основанное на пикселе разрешение дисплея. Эта структура имеет два сохраненных вызванные свойства width и height. Сохраненные свойства являются константами или переменными, которые укутаны и сохранены как часть класса или структуры. Эти два свойства выведены, чтобы иметь тип Int путем установки их в начальное целочисленное значение 0.

Пример выше также определяет новый вызванный класс VideoMode, описать определенный режим видео для видеодисплея. Этот класс имеет сохраненные свойства четырех переменных. Первое, resolution, инициализируется с новым Resolution экземпляр структуры, выводящий тип свойства Resolution. Для других трех свойств, новых VideoMode экземпляры будут инициализированы с interlaced установка false (значение “нечередуемого видео”), частота кадров воспроизведения 0.0, и дополнительное String значение вызывают name. name свойству автоматически дают значение по умолчанию nil, или “нет name оцените”, потому что это имеет дополнительный тип.

Класс и экземпляры структуры

Resolution определение структуры и VideoMode определение класса только описывает что a Resolution или VideoMode будет похож. Они сами не описывают определенное разрешение или режим видео. Чтобы сделать это, необходимо создать экземпляр структуры или класса.

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

  • let someResolution = Resolution()
  • let someVideoMode = VideoMode()

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

Доступ к свойствам

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

  • println("The width of someResolution is \(someResolution.width)")
  • // prints "The width of someResolution is 0"

В этом примере, someResolution.width относится к width свойство someResolution, и возвращает его начальное значение по умолчанию 0.

Можно выполнить развертку в подсвойства, такой как width свойство в resolution свойство a VideoMode:

  • println("The width of someVideoMode is \(someVideoMode.resolution.width)")
  • // prints "The width of someVideoMode is 0"

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

  • someVideoMode.resolution.width = 1280
  • println("The width of someVideoMode is now \(someVideoMode.resolution.width)")
  • // prints "The width of someVideoMode is now 1280"

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

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

  • let vga = Resolution(width: 640, height: 480)

В отличие от структур, экземпляры класса не получают значение по умолчанию memberwise инициализатор. Инициализаторы описаны более подробно в Инициализации.

Структуры и перечисления являются типами значения

Тип значения является типом, значение которого копируется, когда это присваивается переменному или постоянному, или когда это передается функции.

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

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

Рассмотрите этот пример, использующий Resolution структура от предыдущего примера:

  • let hd = Resolution(width: 1920, height: 1080)
  • var cinema = hd

Этот пример объявляет вызванную константу hd и наборы это к a Resolution экземпляр, инициализированный с шириной и высотой видео full HD (1920 пиксели, широкие 1080 пиксели высоко).

Это тогда объявляет вызванную переменную cinema и наборы это к текущей стоимости hd. Поскольку Resolution структура, копия существующего экземпляра сделана, и эта новая копия присваивается cinema. Даже при том, что hd и cinema теперь имейте ту же ширину и высоту, они - два абсолютно различных экземпляра негласно.

Затем, width свойство cinema исправляется, чтобы быть шириной немного более широкого 2K стандарта, используемого для цифровой проекции кино (2048 широкие пиксели и 1080 пиксели высоко):

  • cinema.width = 2048

Проверка width свойство cinema показывает, что это действительно изменилось, чтобы быть 2048:

  • println("cinema is now \(cinema.width) pixels wide")
  • // prints "cinema is now 2048 pixels wide"

Однако width свойство оригинала hd экземпляр все еще имеет старое значение 1920:

  • println("hd is still \(hd.width) pixels wide")
  • // prints "hd is still 1920 pixels wide"

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

То же поведение применяется к перечислениям:

  • enum CompassPoint {
  • case North, South, East, West
  • }
  • var currentDirection = CompassPoint.West
  • let rememberedDirection = currentDirection
  • currentDirection = .East
  • if rememberedDirection == .West {
  • println("The remembered direction is still .West")
  • }
  • // prints "The remembered direction is still .West"

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

Классы являются ссылочными типами

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

Вот пример, с помощью VideoMode класс, определенный выше:

  • let tenEighty = VideoMode()
  • tenEighty.resolution = hd
  • tenEighty.interlaced = true
  • tenEighty.name = "1080i"
  • tenEighty.frameRate = 25.0

Этот пример объявляет новую вызванную константу tenEighty и наборы это для обращения к новому экземпляру VideoMode класс. Режим видео присваивается копия разрешения HD 1920 1080 до. Это установлено быть чередованным и дано имя "1080i". Наконец, это установлено в частоту кадров 25.0 кадры в секунду.

Затем, tenEighty присваивается новой константе, вызванной alsoTenEighty, и частота кадров alsoTenEighty изменяется:

  • let alsoTenEighty = tenEighty
  • alsoTenEighty.frameRate = 30.0

Поскольку классы являются ссылочными типами, tenEighty и alsoTenEighty фактически оба обращаются к тому же VideoMode экземпляр. Эффективно, они - всего два различных имени для того же единственного экземпляра.

Проверка frameRate свойство tenEighty показывает, что это правильно сообщает о новой частоте кадров 30.0 от базового VideoMode экземпляр:

  • println("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
  • // prints "The frameRate property of tenEighty is now 30.0"

Обратите внимание на то, что tenEighty и alsoTenEighty объявляются как константы, а не переменные. Однако можно все еще измениться tenEighty.frameRate и alsoTenEighty.frameRate потому что значения tenEighty и alsoTenEighty сами константы фактически не изменяются. tenEighty и alsoTenEighty самостоятельно не «храните» VideoMode экземпляр — вместо этого, они оба обращаются к a VideoMode экземпляр негласно. Это frameRate свойство базового VideoMode это изменяется, не значения постоянных ссылок на это VideoMode.

Операторы идентификационных данных

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

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

  • Идентичный (===)

  • Не идентичный (!==)

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

  • if tenEighty === alsoTenEighty {
  • println("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
  • }
  • // prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."

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

  • “Идентичный” означает, что две константы или переменные типа класса относятся к точно тому же экземпляру класса.

  • “Равный” означает, что два экземпляра считают «равными» или «эквивалентными» в значении, для некоторого надлежащего значения «равных», как определено разработчиком типа.

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

Указатели

Если у Вас есть опыт с C, C++ или Objective C, можно знать, что эти языки используют указатели для обращения к адресам в памяти. Swift, постоянный или переменный, который относится к экземпляру некоторого ссылочного типа, подобен указателю в C, но не является прямым указателем на адрес в памяти и не требует, чтобы Вы записали звездочку (*) указать, что Вы создаете ссылку. Вместо этого эти ссылки определяются как любая другая константа или переменные в Swift.

Выбор между классами и структурами

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

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

Как общее руководство, рассмотрите создание структуры, когда один или больше этих условий применяйтесь:

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

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

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

  • Структура не должна наследовать свойства или поведение от другого существующего типа.

Примеры хороших кандидатов на структуры включают:

  • Размер геометрической фигуры, возможно инкапсулируя a width свойство и a height свойство, оба из типа Double.

  • Способ относиться к диапазонам в ряду, возможно инкапсулируя a start свойство и a length свойство, оба из типа Int.

  • Точка в 3D системе координат, возможно инкапсулируя x, y и z свойства, каждый тип Double.

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

Присвоение и поведение копии для строк, массивов и словарей

Swift String, Array, и Dictionary типы реализованы как структуры. Это означает, что строки, массивы и словари копируются, когда они присваиваются новой константе или переменные, или когда они передаются функции или методу.

Это поведение отличается от NSString, NSArray, и NSDictionary в Основе, которые реализованы как классы, не структуры. NSString, NSArray, и NSDictionary экземпляры всегда присваиваются и раздаются как ссылка на существующий экземпляр, а не как копия.