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

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

Разработчик

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

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

Наследование

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

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

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

Определение базового класса

Любой класс, не наследовавшийся от другого класса, известен как базовый класс.

Пример ниже определяет вызванный базовый класс Vehicle. Этот базовый класс определяет сохраненное вызванное свойство currentSpeed, со значением по умолчанию 0.0 (выведение типа свойства Double). currentSpeed значение свойства используется вычисленным только для чтения String свойство вызывают description создать описание механизма.

Vehicle базовый класс также определяет вызванный метод makeNoise. Этот метод ничего фактически не делает для основы Vehicle экземпляр, но будет настроен подклассами Vehicle позже:

  • class Vehicle {
  • var currentSpeed = 0.0
  • var description: String {
  • return "traveling at \(currentSpeed) miles per hour"
  • }
  • func makeNoise() {
  • // do nothing - an arbitrary vehicle doesn't necessarily make a noise
  • }
  • }

Вы создаете новый экземпляр Vehicle с синтаксисом инициализатора, записанным как a TypeName сопровождаемый пустыми круглыми скобками:

  • let someVehicle = Vehicle()

Создав новое Vehicle экземпляр, можно получить доступ к description свойство для печати человекочитаемого описания текущей скорости механизма:

  • println("Vehicle: \(someVehicle.description)")
  • // Vehicle: traveling at 0.0 miles per hour

Vehicle класс определяет общие характеристики для произвольного механизма, но не полезен сам по себе. Для создания его более полезным необходимо совершенствовать его для описания более определенных видов механизма.

Разделение на подклассы

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

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

  • class SomeSubclass: SomeSuperclass {
  • // subclass definition goes here
  • }

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

  • class Bicycle: Vehicle {
  • var hasBasket = false
  • }

Новое Bicycle класс автоматически получает все характеристики Vehicle, такой как currentSpeed и description свойства и makeNoise() метод.

В дополнение к характеристикам это наследовалось, Bicycle класс определяет новое сохраненное свойство, hasBasket, со значением по умолчанию false (выведение типа Bool для свойства).

По умолчанию, любой новый Bicycle экземпляр, который Вы создаете, не будет иметь корзины. Можно установить hasBasket свойство к true для детали Bicycle экземпляр после того экземпляра создается:

  • let bicycle = Bicycle()
  • bicycle.hasBasket = true

Можно также изменить наследованный currentSpeed свойство a Bicycle экземпляр и запрос экземпляр наследовались description свойство:

  • bicycle.currentSpeed = 15.0
  • println("Bicycle: \(bicycle.description)")
  • // Bicycle: traveling at 15.0 miles per hour

Подклассы могут самостоятельно быть разделены на подклассы. Следующий пример создает подкласс Bicycle для двухместного велосипеда, известного как «тандем»:

  • class Tandem: Bicycle {
  • var currentNumberOfPassengers = 0
  • }

Tandem наследовал все свойства и методы от Bicycle, который поочередно наследовал все свойства и методы от Vehicle. Tandem подкласс также добавляет новое сохраненное вызванное свойство currentNumberOfPassengers, со значением по умолчанию 0.

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

  • let tandem = Tandem()
  • tandem.hasBasket = true
  • tandem.currentNumberOfPassengers = 2
  • tandem.currentSpeed = 22.0
  • println("Tandem: \(tandem.description)")
  • // Tandem: traveling at 22.0 miles per hour

Переопределение

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

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

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

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

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

Где это является надлежащим, Вы получаете доступ к версии суперкласса метода, свойства или нижнего индекса при помощи super префикс:

  • Переопределенный метод называют someMethod() может вызвать версию суперкласса someMethod() путем вызова super.someMethod() в реализации метода переопределения.

  • Переопределенное свойство вызывают someProperty может получить доступ к версии суперкласса someProperty как super.someProperty в переопределяющем методе get или реализации метода set.

  • Переопределенный нижний индекс для someIndex может получить доступ к версии суперкласса того же нижнего индекса как super[someIndex] из переопределяющей нижней реализации.

Методы переопределения

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

Следующий пример определяет новый подкласс Vehicle вызванный Train, который переопределяет makeNoise() метод это Train наследовался от Vehicle:

  • class Train: Vehicle {
  • override func makeNoise() {
  • println("Choo Choo")
  • }
  • }

Если Вы создаете новый экземпляр Train и вызовите makeNoise() метод, Вы видите что Train версию подкласса метода вызывают:

  • let train = Train()
  • train.makeNoise()
  • // prints "Choo Choo"

Переопределение свойств

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

Переопределение методов get свойства и методов set

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

Можно представить наследованное свойство только для чтения как свойство чтения/записи путем обеспечения и метода get и метода set в переопределении свойства подкласса. Вы не можете, однако, представить наследованное свойство чтения/записи как свойство только для чтения.

Следующий пример определяет новый вызванный класс Car, который является подклассом Vehicle. Car класс представляет новое сохраненное вызванное свойство gear, с целочисленным значением по умолчанию 1. Car класс также переопределяет description свойство это наследовалось от Vehicle, предоставлять пользовательское описание, включающее текущее имущество:

  • class Car: Vehicle {
  • var gear = 1
  • override var description: String {
  • return super.description + " in gear \(gear)"
  • }
  • }

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

Если Вы создаете экземпляр Car класс и набор gear и currentSpeed свойства, Вы видите что description свойство возвращает адаптированное описание, определенное в Car класс:

  • let car = Car()
  • car.currentSpeed = 25.0
  • car.gear = 3
  • println("Car: \(car.description)")
  • // Car: traveling at 25.0 miles per hour in gear 3

Переопределение наблюдателей свойства

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

Следующий пример определяет новый вызванный класс AutomaticCar, который является подклассом Car. AutomaticCar класс представляет автомобиль с автоматической коробкой передач, автоматически выбирающей надлежащее имущество для использования на основе текущей скорости:

  • class AutomaticCar: Car {
  • override var currentSpeed: Double {
  • didSet {
  • gear = Int(currentSpeed / 10.0) + 1
  • }
  • }
  • }

Каждый раз, когда Вы устанавливаете currentSpeed свойство AutomaticCar экземпляр, свойство didSet наблюдатель устанавливает экземпляр gear свойство к надлежащему выбору имущества для новой скорости. В частности наблюдатель свойства выбирает имущество, которое является новым currentSpeed значение, разделенное на 10, округленный в меньшую сторону до самого близкого целого числа, плюс 1. Скорость 35.0 производит имущество 4:

  • let automatic = AutomaticCar()
  • automatic.currentSpeed = 35.0
  • println("AutomaticCar: \(automatic.description)")
  • // AutomaticCar: traveling at 35.0 miles per hour in gear 4

Предотвращение переопределений

Можно предотвратить метод, свойство, или преобразовать в нижний индекс от того, чтобы быть переопределенным путем маркировки его как финал. Сделайте это путем записи final модификатор перед методом, свойством или introducer ключевым словом нижнего индекса (такой как final var, final func, final class func, и final subscript).

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

Можно отметить весь класс как финал путем записи final модификатор перед class ключевое слово в его определении класса (final class). О любой попытке разделить заключительный класс на подклассы сообщают как ошибка времени компиляции.