Свойства предназначены для хранения состояния объекта. Свойства бывают двух типов:
Хранимые свойства (stored properties) - переменные или константы, определенные на уровне класса или структуры
Вычисляемые свойства (computed properties) - конструкции, динамически вычисляющие значения. Могут применяться в классе, перечислении или структуре
Хранимые свойства представляют простейшую форму хранения значений в виде констант или переменных:
class User { var age: Int = 22 let name: String = "" }
При определении хранимых свойств следует предоставить им значения по умолчанию либо напрямую, либо в одном из инициализаторов класса:
class User { var age: Int let name: String init(){ name = "Tom" age = 22 } }
После определения свойств класса мы можем получить к ним доступ:
var user: User = User() print(user.age) // 22 print(user.name) // Tom
Ленивые хранимые свойства (lazy stored properties) представляют такие свойства, значение которых устанавливается при первом обращении к ним. Использование подобных свойств позволяет более эффективно использовать память, не загромождая ее ненужными объектами, которые могут не потребоваться.
Ленивые свойства определяются с помощью ключевого слова lazy:
class User { lazy var age: Int = 22 lazy var name: String = "Tom" }
Модификатор lazy может использоваться только для свойств, которые определяются с помощью var.
Вычисляемые свойства (computed properties) не хранят значения, а динамически вычисляют его, используя блок get (getter). Также они могут содержать вспомогательные блок set (setter), который может применяться для установки значения.
Общий синтаксис определения вычисляемого свойства следующий:
var имя_свойства: тип { get { //вычисление значения } set (параметр) { // установка значения } }
Блок get или геттер срабатывает при получении значения свойства. Для возвращения значения должен использоваться оператор return.
Блок set или сеттер срабатывает при установке нового значения. При этом в качестве параметра в блок передается устанавливаемое значение.
Рассмотрим следующий пример. Допустим, у нас есть программа, которая вычисляет прибыль при вложеннии определенной суммы на определенный период:
class Account{ var capital: Double = 0 // сумма вклада var rate: Double = 0.01 // процентная ставки var profit: Double{ get{ return capital + capital * rate } set(newProfit){ self.capital = newProfit / (1 + rate) } } init(capital: Double, rate: Double){ self.capital = capital self.rate = rate } } var myAcc: Account = Account (capital: 1000, rate: 0.1) print (myAcc.profit) // 1100 // ожидаемая прибыль myAcc.profit = 1210 print(myAcc.capital) // 1100 - необходимая сумма вклада для получения этой прибыли
Свойство profit представляет вычисляемое свойство. Его блок get возвращает результат арифметических операций:
get{ return capital + capital * rate }
В данном случае этот блок срабатывает, когда мы обращаемся к свойству profit:
print (myAcc.profit)
Блок set позволяет реализовать обратную связь между суммой прибыли и суммой вклада: мы вводим ожидаемую прибыль и получим сумму вклада, необходимую для получения этой прибыли:
set(newProfit){ self.capital = newProfit / (1 + rate) }
Этот блок срабатывает при установке значения:
myAcc.profit = 1210
Параметр newProfit в блоке set это и есть присваиваемое значение 1210. newProfit - это случайное название параметра, которое может быть любым, важно понимать, что оно передает значение типа, которое представляет свойство - типа Double.
Также мы можем использовать сокращенную форму блока set:
set{ self.capital = newValue / (1 + rate) }
Переданное значение теперь передается через ключевое слово newValue.
Не всегда в вычисляемых свойствах необходим блок set. Иногда нам не нужно устанавливать новое значение свойства, а требуется только возвратить его. В этом случае мы можем опустить блок set и создать свойство только для чтения (read-only computed property):
class Account{ var capital: Double = 0 // сумма вклада var rate: Double = 0.01 // процентная ставки var profit: Double{ return capital + capital * rate } init(capital: Double, rate: Double){ self.capital = capital self.rate = rate } } var myAcc: Account = Account (capital: 1000, rate: 0.1) print (myAcc.profit) // 1100
Наблюдатели свойств (property observers) следят за изменением значений свойств и при необходимости могут реагировать на эти изменения. Обозреватели свойств вызываются каждый раз при установке нового значения свойства, даже если новое значение не отличается от старого.
Наблюдатели свойств могут быть двух типов:
willSet: вызывается перед установкой нового значения
didSet: вызывается после установки нового значения
Общий синтаксис наблюдателей свойств можно выразить следующим образом:
var свойство: тип { willSet (параметр){ // выражения } didSet (параметр){ // выражения } }
Применим наблюдатели свойств:
class Account{ var capital: Double { willSet (newCapital){ print("Старая сумма вклада: \(self.capital) Новая сумма: \(newCapital)") } didSet (oldCapital){ print("Сумма вклада увеличена на \(self.capital - oldCapital)") } } var rate: Double init(capital: Double, rate: Double){ self.capital = capital self.rate = rate } } var myAcc: Account = Account(capital: 1000, rate: 0.1) myAcc.capital = 1200 // вывод консоли // "Старая сумма вклада: 1000 Новая сумма: 1200" // "Сумма вклада увеличена на 200"