Properties In Swift


Properties associate values with a particular class, structure, and enumeration. Stored property stores constants and values as a part of the instance, whereas computed property (rather than the store) calculates a value.
Properties are classified into the following types.
  • Stored Properties
  • Computed Properties 
Stored and computed properties are usually associated with instances of a particular type. However, properties can also be associated with the type itself. Such properties are known as type properties.

Stored Properties

A stored property is a constant or variable that is stored as part of an instance of a particular class or structure. Stored properties can be either variable or stored properties. Variable stored property is declared with Var keyword or constant stored is declared with the let keyword. 
Below FixedLenthRange Structure describes the range of integers whose range length can't be changed after it is created.
  1. struct FixedLengthRange {  
  2.     var firstValue: Int  
  3.     let length: Int  
  4. }  
  5. var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)  
  6. // the range represents integer values 0, 1, and 2  
  7. rangeOfThreeItems.firstValue = 6  
  8. // the range now represents integer values 6, 7, and 8  
Above Structures instances have a variable stored property called firstValue and constant stored property is called length. 

Constant Stored Property Instances

When you create an instance of a structure and assign that instance to a constant, you can't modify the instance properties, even if they were declared as variable properties - Example
  1. let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)  
  2. // this range represents integer values 0, 1, 2, and 3  
  3. rangeOfFourItems.firstValue = 6  
  4. // this will report an error, even though firstValue is a variable property  
Above code rangeOfFourItems are declared as a constant stored property instance with let keyword, you can't modify firstValue constant stored property, even though firstValue declare as a var.
  • This behavior is due to structures being value types.
  • The same is not true for classes, Which is reference types. If you assign an instance of reference type to constant, you can still change that instance's variable properties.

Lazy Stored Properties

A lazy stored property is a property, whose initial value is not calculated until the first time it is used. You can declare a lazy stored property with modifier  before its declaration.
  1. import UIKit  
  2. struct SquareNumber {  
  3.     var number = 7  
  4.     lazy var squareOfNumber: Int = {  
  5.         return square(of: self.number)  
  6.     }()  
  7.     func square(of num: Int) -> Int {  
  8.         return num*num  
  9.     }  
  10. }  
  11. var sqNumber = SquareNumber()  
  12. print(sqNumber.squareOfNumber)  

Lazy Rules

  1. You can't use lazy with let keyword, You must declare a lazy property as a variable(with var keyword) because its initial value might not be retrieved until after instance initialization completes.
  2. You can't use lazy with computed property, because of a computed property returns the value every time we try to access it after executing the code inside the computation block.
  3. You can use lazy with the only member of the class and struct.
  4. Lazy property is not initialized atomically so it is not threaded safe.

Lazy Stored Property vs Stored Property

  1. There are a few advantages of  Lazy stored property over Stored property -
  2. The closure associated with the lazy property is executed only if you used that property. If for some reason that property is not used you avoid unnecessary allocation and computation.
  3. You can populate a lazy property with the value of stored property. 
  4. You can use self inside the closure of a lazy property. It will not cause any retain cycles.

Computed Property

Computed properties can define in classes, structures, and enumeration, which don't actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.
  1. struct Person{  
  2.     var name = "Pravesh Dubey"  
  3.     var favoriteSport = "Cricket"  
  4.     var favoritePlayer = "Rohit Sharma"  
  5.     var greeting:String{  
  6.         return "Hello my name is \(name),and I like to play \(favoriteSport) and my favorite player is \(favoritePlayer)"  
  7.     }  
  8. }  
  9. let personObj = Person()  
  10. print(personObj.greeting)    
  11. Output: Hello my name is Pravesh Dubey, and I like to play Cricket and my favorite player is Rohit Sharma  

Read-Only Computed Property

A computed property with a getter but no setter is known as a read-only computed property. A read-only computed property always returns a value and can be accessed through dot syntax, but cannot be set to a different value.
  1. struct Cuboid {  
  2.     var width = 0.0, height = 0.0, depth = 0.0  
  3.     var volume: Double {  
  4.         return width * height * depth  
  5.     }  
  6. }  
  7. let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)  
  8. print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")  
  9. Output : the valume of fourByFiveByTwo is 40.0
You must declare computed properties including read-only computed properties as variable properties with the var keyword because their value is not fixed. The let keyword is only used for constant properties which indicate that values cannot be changed once they are set at the time of instance initialization.

Property Observers

Property observers observe and respond to changes in a property's value. Property observers are called every time a property's value is set, even if the new value is the same as the property's current value.
You can add Property Observer in the following cases,
  1. You can add property observers to any stored properties you define, except for lazy stored properties.
  2. You can add any inherited property(whether stored or computed) by overriding the property within a subclass.
  3. You don't need to define property observers for nonoverridden computed properties, because you can observe and respond to changes to their value in the computed property's setter.
You have two options to define property observers,
  • willSet is called just before the value is stored.
  • didSet is called immediately after the new value is stored.
  1. class StepCounter {  
  2.     var totalSteps: Int = 0 {  
  3.         willSet(newTotalSteps) {  
  4.             print("About to set totalSteps to \(newTotalSteps)")  
  5.         }  
  6.         didSet {  
  7.             if totalSteps > oldValue  {  
  8.                 print("Added \(totalSteps - oldValue) steps")  
  9.             }  
  10.         }  
  11.     }  
  12. }  
  13. let stepCounter = StepCounter()  
  14. stepCounter.totalSteps = 200  
  15. // About to set totalSteps to 200  
  16. // Added 200 steps   
If you pass a property that has observers to a function as an in-out parameter, the willSet, and didSet observers are always called.