Свойства – переменные ассоциированные с классом, структурой или перечислением. Они бывают нескольких видов:
Stored Properties – хранимые свойства:
Обычные свойства, могут быть как изменяемыми var, так и константами let
1 2 3 4 5 6 7 8 9 |
struct Variables { let sampleConstant : Int var sampleVariable : String } var mutlableStruct = Variables(sampleConstant: 10, sampleVariable: "test") mutlableStruct.sampleVariable = "newstring" mutlableStruct.sampleConstant = 4 // ошибка, константа |
Но если бы мы определили экземпляр структуры как константу а не переменную, мы не смогли бы изменить даже свойство которое объявлено как переменная, т.к. структура – значимого типа и изменение свойства внутри структуры означает изменение всей структуры, а она объявлена как константа.
let constantStruct = Variables(sampleConstant: 10, sampleVariable: “test”)
constantStruct.sampleVariable = “newstring” // ошибка
Для классов это неверно, у экземпляра класса объявленного как константа можно менять значение переменных свойств.
Lazy Stored Properties – ленивые свойства:
Вычисляются в момент первого обращения, помечаются как lazy, не могут быть константой. Применяются когда создание класса требует больших затрат и это используется редко
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class CacheStore { // инициализация - высоко затратная операция func getFile(name: String) {} : File } class SampleClass { lazy var cache = CacheStore() } var sampleClass = SampleClass() sampleClass.cache.getFile("flower.jpg") // только в этот момент, при обращении к переменной cache - произойдет ее создание |
Computed Properties – вычисляемые свойства:
Свойства, значения которых вычисляется заново при каждом обращении
1 2 3 4 5 6 7 8 9 10 |
class Distance { var time = 1 var velocity = 0 var path : Int { get { return time * velocity } set (newPath) { velocity = newPath / time } } } |
path – вычисляемое свойство, оно имееет get – позволяющее получить его значение, и set – выставить
1 2 3 4 5 6 7 |
var distance = Distance() distance.time = 10 distance.velocity = 100 print(distance.path) // 1000 distance.path = 500 print(distance.velocity) // 50 |
Если не указывать явно имя (newPath), то по умолчанию будет использовано newValue
1 2 3 |
set { velocity = newValue / time } |
set тут конечно явно притянутый за уши, но ради демонстрации синтаксиса – пусть будет. Но в данном примере явно будет лучше без него, таким образом свойство станет только для чтения (обозначить как let все равно нельзя, т.к. оно каждый раз вычисляется и по сути является переменной)
Property Observers – наблюдатели за свойством:
Позволяет прикреплять наблюдателя к хранимым свойствам, включая наследуемые, кроме ленивых (lazy)
Если свойства не наследуемое – смысла прикреплять наблюдателя нет, проще вставить необходимый код в set
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Bill { var amount: Int = 0 { willSet (newAmount) { // по умолчанию newValue print("Новое значение счета: \(newAmount)") } didSet { if(amount >= 0) { print("Старое значение счета: \(oldValue)") } else { print("У нас без долгов, выставляем 0") amount = 0 } } } } |
Код из willSet вызовется перед изменением значения. Код из didSet, после выставления значения. Причем во время выполнения кода didSet, мы можем получить доступ к старому значению через oldValue, и изменить значение этого свойства по имени как вышеприведенном примере – защита от отрицательных значений
1 2 3 4 5 6 7 8 9 10 11 12 |
var bill = Bill() bill.amount = 100 //Новое значение счета: 100 //Старое значение счета: 0 bill.amount = 200 //Новое значение счета: 200 //Старое значение счета: 100 bill.amount = -100 //Новое значение счета: -100 //У нас без долгов, выставляем 0 //0 print(bill.amount) // 0 |
Глобальные переменные и константы всегда вычисляются лениво, при этом помечать как lazy их не нужно
Локальные – никогда
Type Properties (Свойства типа известные в C как статические):
Свойства относящиеся к типу, а не конкретному экземпляру
У значимых типов бывают – хранимыми и вычисляемыми, для ссылочных типов – только вычисляемыми.
1 2 3 4 5 6 7 8 9 |
class SomeClass { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { return 0 } class var overrideableComputedTypeProperty: Int { return 0 } } |
Ключевое слово class означает что данное свойство можно переопределить у потомков (только для ссылочных типов)
Доступ – стандартен, по точке но от Типа, а не экземпляра
1 |
SomeClass.storedTypeProperty = "New" |