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

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

Разработчик

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

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

Свойства

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

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

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

Сохраненные свойства

В его самой простой форме сохраненное свойство является константой или переменный, который сохранен как часть экземпляра определенного класса или структуры. Сохраненные свойства могут быть любой переменными сохраненными свойствами (представленный var ключевое слово) или постоянные сохраненные свойства (представленный let ключевое слово).

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

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

  • struct FixedLengthRange {
  • var firstValue: Int
  • let length: Int
  • }
  • var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
  • // the range represents integer values 0, 1, and 2
  • rangeOfThreeItems.firstValue = 6
  • // the range now represents integer values 6, 7, and 8

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

Сохраненные свойства постоянных экземпляров структуры

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

  • let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
  • // this range represents integer values 0, 1, 2, and 3
  • rangeOfFourItems.firstValue = 6
  • // this will report an error, even though firstValue is a variable property

Поскольку rangeOfFourItems объявляется как константа (с let ключевое слово), не возможно изменить firstValue свойство, даже при том, что firstValue переменное свойство.

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

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

Ленивые сохраненные свойства

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

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

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

  • class DataImporter {
  • /*
  • DataImporter is a class to import data from an external file.
  • The class is assumed to take a non-trivial amount of time to initialize.
  • */
  • var fileName = "data.txt"
  • // the DataImporter class would provide data importing functionality here
  • }
  • class DataManager {
  • lazy var importer = DataImporter()
  • var data = [String]()
  • // the DataManager class would provide data management functionality here
  • }
  • let manager = DataManager()
  • manager.data.append("Some data")
  • manager.data.append("Some more data")
  • // the DataImporter instance for the importer property has not yet been created

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

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

Это возможно для a DataManager экземпляр для управления его данными, никогда не импортируя данные из файла, таким образом, нет никакой потребности создать новое DataImporter экземпляр, когда DataManager самостоятельно создается. Вместо этого имеет больше смысла создавать DataImporter экземпляр, если и когда это сначала используется.

Поскольку это отмечено с lazy модификатор, DataImporter экземпляр для importer свойство только создается когда importer к свойству сначала получают доступ, такой как тогда, когда fileName свойство запрашивается:

  • println(manager.importer.fileName)
  • // the DataImporter instance for the importer property has now been created
  • // prints "data.txt"

Сохраненные свойства и переменные экземпляра

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

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

Вычисленные свойства

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

  • struct Point {
  • var x = 0.0, y = 0.0
  • }
  • struct Size {
  • var width = 0.0, height = 0.0
  • }
  • struct Rect {
  • var origin = Point()
  • var size = Size()
  • var center: Point {
  • get {
  • let centerX = origin.x + (size.width / 2)
  • let centerY = origin.y + (size.height / 2)
  • return Point(x: centerX, y: centerY)
  • }
  • set(newCenter) {
  • origin.x = newCenter.x - (size.width / 2)
  • origin.y = newCenter.y - (size.height / 2)
  • }
  • }
  • }
  • var square = Rect(origin: Point(x: 0.0, y: 0.0),
  • size: Size(width: 10.0, height: 10.0))
  • let initialSquareCenter = square.center
  • square.center = Point(x: 15.0, y: 15.0)
  • println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
  • // prints "square.origin is now at (10.0, 10.0)"

Этот пример определяет три структуры для работы с геометрическими фигурами:

  • Point инкапсулирует (x, y) координата.

  • Size инкапсулирует a width и a height.

  • Rect определяет прямоугольник точкой источника и размером.

Rect структура также обеспечивает вычисленное вызванное свойство center. Текущая центральная позиция a Rect может всегда определяться от origin и size, и таким образом, Вы не должны хранить центральную точку как явное Point значение. Вместо этого Rect определяет пользовательского метода get и метод set для вычисленной вызванной переменной center, позволять Вам работать с прямоугольником center как будто это было реальное сохраненное свойство.

Предыдущий пример создает новое Rect переменную вызывают square. square переменная инициализируется с точкой источника (0, 0), и ширина и высота 10. Этот квадрат представлен синим квадратом в схеме ниже.

square переменная center к свойству тогда получают доступ через точечный синтаксис (square.center), который вызывает метода get для center быть вызванным, получать текущее значение свойства. Вместо того, чтобы возвращать существующее значение, метод get фактически вычисляет и возвращает новое Point представлять центр квадрата. Как видно вышеупомянутого метод get правильно возвращает центральную точку (5, 5).

center свойство тогда установлено в новое значение (15, 15), который повышает квадрат и вправо к новой позиции, показанной оранжевым квадратом в схеме ниже. Установка center свойство вызывает метод set для center, который изменяет x и y значения сохраненного origin свойство и перемещения квадрат к его новой позиции.

image: ../Art/computedProperties_2x.png

Краткое объявление метода set

Если метод set вычисленного свойства не определяет имя для нового значения, которое будет установлено, имя по умолчанию newValue используется. Вот альтернативная версия Rect структура, использующая в своих интересах эту краткую нотацию:

  • struct AlternativeRect {
  • var origin = Point()
  • var size = Size()
  • var center: Point {
  • get {
  • let centerX = origin.x + (size.width / 2)
  • let centerY = origin.y + (size.height / 2)
  • return Point(x: centerX, y: centerY)
  • }
  • set {
  • origin.x = newValue.x - (size.width / 2)
  • origin.y = newValue.y - (size.height / 2)
  • }
  • }
  • }

Вычисленные свойства только для чтения

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

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

  • struct Cuboid {
  • var width = 0.0, height = 0.0, depth = 0.0
  • var volume: Double {
  • return width * height * depth
  • }
  • }
  • let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
  • println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
  • // prints "the volume of fourByFiveByTwo is 40.0"

Этот пример определяет новую вызванную структуру Cuboid, который представляет 3D прямоугольник с width, height, и depth свойства. Эта структура также имеет вычисленное вызванное свойство только для чтения volume, который вычисляет и возвращает текущий объем кубоида. Это не целесообразно для volume быть устанавливаемым, потому что это было бы неоднозначно относительно который значения width, height, и depth должен использоваться для детали volume значение. Тем не менее, это полезно для a Cuboid обеспечить вычисленное свойство только для чтения, чтобы позволить внешним пользователям обнаружить его текущий расчетный объем.

Наблюдатели свойства

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

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

У Вас есть опция определить или или оба из этих наблюдателей на свойстве:

  • willSet вызывается непосредственно перед тем, как значение сохранено.

  • didSet сразу вызывается после того, как новое значение сохранено.

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

Точно так же, если Вы реализуете a didSet наблюдатель, это будет передано постоянный параметр, содержащий старое значение свойства. Если Вы желаете или используете название параметра по умолчанию, можно назвать параметр oldValue.

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

  • class StepCounter {
  • var totalSteps: Int = 0 {
  • willSet(newTotalSteps) {
  • println("About to set totalSteps to \(newTotalSteps)")
  • }
  • didSet {
  • if totalSteps > oldValue {
  • println("Added \(totalSteps - oldValue) steps")
  • }
  • }
  • }
  • }
  • let stepCounter = StepCounter()
  • stepCounter.totalSteps = 200
  • // About to set totalSteps to 200
  • // Added 200 steps
  • stepCounter.totalSteps = 360
  • // About to set totalSteps to 360
  • // Added 160 steps
  • stepCounter.totalSteps = 896
  • // About to set totalSteps to 896
  • // Added 536 steps

StepCounter класс объявляет a totalSteps свойство типа Int. Это - сохраненное свойство с willSet и didSet наблюдатели.

willSet и didSet наблюдатели для totalSteps вызываются каждый раз, когда свойство присваивается новое значение. Даже если новое значение совпадает с текущей стоимостью, это - истина.

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

didSet наблюдателя вызывают после значения totalSteps обновляется. Это сравнивает новое значение totalSteps против старого значения. Если общее количество шагов увеличилось, сообщение распечатано для указания, сколько новых шагов было предпринято. didSet наблюдатель не обеспечивает пользовательское название параметра для старого значения и имя по умолчанию oldValue используется вместо этого.

Глобальные и локальные переменные

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

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

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

Введите свойства

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

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

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

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

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

Введите синтаксис свойства

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

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

  • struct SomeStructure {
  • static var storedTypeProperty = "Some value."
  • static var computedTypeProperty: Int {
  • // return an Int value here
  • }
  • }
  • enum SomeEnumeration {
  • static var storedTypeProperty = "Some value."
  • static var computedTypeProperty: Int {
  • // return an Int value here
  • }
  • }
  • class SomeClass {
  • static var storedTypeProperty = "Some value."
  • static var computedTypeProperty: Int {
  • // return an Int value here
  • }
  • class var overrideableComputedTypeProperty: Int {
  • // return an Int value here
  • }
  • }

Запросы и установка свойств типа

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

  • println(SomeClass.computedTypeProperty)
  • // prints "42"
  • println(SomeStructure.storedTypeProperty)
  • // prints "Some value."
  • SomeStructure.storedTypeProperty = "Another value."
  • println(SomeStructure.storedTypeProperty)
  • // prints "Another value."

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

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

image: ../Art/staticPropertiesVUMeter_2x.png

Звуковые каналы, описанные выше, представлены экземплярами AudioChannel структура:

  • struct AudioChannel {
  • static let thresholdLevel = 10
  • static var maxInputLevelForAllChannels = 0
  • var currentLevel: Int = 0 {
  • didSet {
  • if currentLevel > AudioChannel.thresholdLevel {
  • // cap the new audio level to the threshold level
  • currentLevel = AudioChannel.thresholdLevel
  • }
  • if currentLevel > AudioChannel.maxInputLevelForAllChannels {
  • // store this as the new overall maximum input level
  • AudioChannel.maxInputLevelForAllChannels = currentLevel
  • }
  • }
  • }
  • }

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

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

AudioChannel структура также определяет сохраненное вызванное свойство экземпляра currentLevel, который представляет текущий уровень звука канала в масштабе 0 к 10.

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

  • Если новое значение currentLevel больше, чем позволенный thresholdLevel, прописные буквы наблюдателя свойства currentLevel к thresholdLevel.

  • Если новое значение currentLevel (после любого ограничения), выше, чем какое-либо значение, ранее полученное любым AudioChannel экземпляр, наблюдатель свойства хранит новое currentLevel значение в maxInputLevelForAllChannels введите свойство.

Можно использовать AudioChannel структура для создания двух новых вызванных звуковых каналов leftChannel и rightChannel, представлять уровни звука аудиосистемы стерео:

  • var leftChannel = AudioChannel()
  • var rightChannel = AudioChannel()

Если Вы устанавливаете currentLevel из левого канала к 7, Вы видите что maxInputLevelForAllChannels свойство типа обновляется для равенства 7:

  • leftChannel.currentLevel = 7
  • println(leftChannel.currentLevel)
  • // prints "7"
  • println(AudioChannel.maxInputLevelForAllChannels)
  • // prints "7"

При попытке установить currentLevel из правильного канала к 11, Вы видите что правильный канал currentLevel свойство ограничивается к максимальному значению 10, и maxInputLevelForAllChannels свойство типа обновляется для равенства 10:

  • rightChannel.currentLevel = 11
  • println(rightChannel.currentLevel)
  • // prints "10"
  • println(AudioChannel.maxInputLevelForAllChannels)
  • // prints "10"