Swift - Properties



Properties are the variables or constants that are related to a particular class, structure or enumeration. They are generally used to define the characteristics of instances of class, structure or enumeration. Properties can be further classified into Stored properties and Computed properties. Stored properties are used to Store constant and variable values as an instance whereas computed properties are used to calculate a value rather than storing the value.

Both Stored and Computed properties are associated with instance type. When the properties are associated with its type values then it is defined as 'Type 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

The stored property stores the constant or variable values as a part of an instance of a particular class or structure. They can be either variable stored property or constant stored property. The stored properties of constants are defined by the 'let' keyword and Stored properties of variables are defined by the 'var' keyword.

During the definition of stored property, we are allowed to provide 'default value’. Also at the time of initialization, we can initialize and modify the initial values of the stored property.

Syntax

Following is the syntax of stored property −

struct structureName{
   var propertyName = initialValue
   let propertyName = initialValue
}

Example

Swift program to demonstrate properties in structure.

// Structure
struct Number {

   // Stored Property without default value
   var digits: Int
    
   // Stored Property with default value
   let pi = 3.1415
}
// Instance of structure
var n = Number(digits: 12345)

// Assigning a value to the property
n.digits = 67

// Accessing the properties of the structure
print("\(n.digits)")
print("\(n.pi)")

Output

It will produce the following output −

67
3.1415

Example

Another method to have stored property is to have constant structures. So the whole instance of the structures will be considered as 'Stored Properties of Constants'.

// Structure 
struct Number{

   // Variable Stored Properties
   var digits: Int
    
   // Constant stored property
   let numbers = 3.1415
}

// Constant Instance of structure
let n = Number(digits: 12345)

// Accessing the properties of structure
print("\(n.digits)")
print("\(n.numbers)")

/* Structure is a value type so when the instance of 
   the structure is marked as a constant type, then all 
   the properties of that structure is also considered as a constant 
   so we wouldn't be able to change the value of the properties even
   if they are of variable type. But this case doesn't happen in class
   because a class is a reference type
*/
n.numbers = 8.7

Output

It will produce the following output −

main.swift:25:3: error: cannot assign to property: 'numbers' is a 'let' constant
n.numbers = 8.7
~~^~~~~~~
main.swift:8:4: note: change 'let' to 'var' to make it mutable
   let numbers = 3.1415
   ^~~
   var

Instead of reinitializing the 'number' to 8.7, it will return an error message indicating that the 'number' is declared as constant.

Lazy Stored Property

Swift provides a flexible property called 'Lazy Stored Property’, whose initial value is not calculated until the first time it is used. Such types of properties are useful when the initial value of a property is expensive to create, when the initial value is not required immediately, etc.

To declare a stored property as a lazy stored property, we have to use a lazy modifier before the variable declaration. Also, the lazy property is always of variable type because the initial value of the lazy property may not be retrieved until the initialization of the instance has been completed. Whereas the constant property always has value before initialisation and we cannot change the value of the constant property so they are not allowed to declare as lazy property.

Syntax

Following is the syntax of lazy stored property −

class structureName{
   lazy var propertyName = 
}

Example

Swift program to demonstrate lazy property in class.

// Define a class named 'sample'
class Sample {
    
   // Lazy property of type 'number'
   lazy var no = Number()
}

// Define a class named 'number'
class Number {
    
   // Property 
   var name = "Swift"
}

// Create an instance of 'Sample' class
var firstSample = Sample()

// Accessing the lazy property 'no' and then accessing its 'name' property
print(firstSample.no.name)

Output

It will produce the following output −

Swift

Instance Variables

In Objective C, Stored properties also have instance variables for backup purposes to store the values declared in stored property.

Swift 4 integrates both these concepts into a single 'stored property' declaration. Instead of having a corresponding instance variable and backup value 'stored property' contains all integrated information defined in a single location about the variable property by variable name, data type and memory management functionalities.

Computed Properties

Apart from stored property Swift also supports one more type of property which is computed property. Computed property does not store values directly instead it provides a getter and an optional setter to retrieve and set other properties and values indirectly. Where the getter method is called when we want to access the property and the setter method is called when we want to modify the property.

To declare a computed property we have to always use the var keyword along with the property name type and the braces{} that contain getter and setter.

Syntax

Following is the syntax of computed property −

struct structureName{
   var propertyName : propertyType{
      get{}
      set{}
   }
}

Example

Swift program to demonstrate computed property in the class.

// Class
class sample {

   // Stored properties
   var no1 = 0.0, no2 = 0.0
   var length = 300.0, breadth = 150.0
    
   // Computed properties
   var middle: (Double, Double) {
      get{
         return (length / 2, breadth / 2)
      }
      set(axis){
         no1 = axis.0 - (length / 2)
         no2 = axis.1 - (breadth / 2)
      }
   }
}

// Instance of class 
var result = sample()

// Accessing and initializing properties
print(result.middle)
result.middle = (0.0, 10.0)

print(result.no1)               
print(result.no2) 

Output

It will produce the following output −

(150.0, 75.0)
-150.0
-65.0

When a computed property leaves the new value as undefined, the default value will be set for that particular variable.

Computed Properties as Read-Only Properties

A read-only property in computed property is defined as a property with getter but no setter. It is always used to return a value. The variables are further accessed through a '.' Syntax but cannot be set to another value.

Example

class film {
   var head = ""
   var duration = 0.0
   
   // Computed property as a read-only property
   var metaInfo: [String:String] {
      return [
         "head": self.head,
         "duration":"\(self.duration)"
      ]
   }
}

// Instance of class
var movie = film()

// Initialzing and accessing properties
movie.head = "Swift Properties"
movie.duration = 3.09
print(movie.metaInfo["head"]!)
print(movie.metaInfo["duration"]!)
Output

It will produce the following output −

Swift Properties
3.09

Property Observers

Property observer allows us to observe and respond to the changes that happen in the value of the property. Whenever the value of the property is set or even if the new value is equal to the current value still the property observer called.

Property observers are available for both stored and computed properties and also available if the property is defined or inherited. For inherited property (either stored or computed) add property observer by overriding the specified property of the inherited class or subclass and for defined computed property, we can use property setter instead of property observer.

Swift supports two types of property observers −

  • willSet − It is called just before the value of the property is stored. It passes a constant parameter as a new value of the property. We are allowed to specify the name of the parameter in the implementation of willSet. If we do not provide the name of the parameter, then it will provide a default parameter with the name ‘newValue’ that represents the new value of the given property.

  • didSet − It is called immediately after the new value of the property is set. It passes a constant parameter that contains the old value of the property. We are allowed to specify the name of the parameter in the implementation of didSet. If we do not provide the name of the parameter, then it will provide a default parameter with the name ‘oldValue’ that represents the old value of the given property.

Example

// Define class
class Samplepgm {
   var counter: Int = 0{
    
      // WillSwt property observer
      willSet(newTotal){
         print("Total Counter is: \(newTotal)")
      }
        
      // didSet property observer
      didSet{
         if counter > oldValue {
            print("Newly Added Counter \(counter - oldValue)")
         }
      }
   }
}

// Instance of class
let NewCounter = Samplepgm()

// Accessing property
NewCounter.counter = 100
NewCounter.counter = 800

Output

It will produce the following output −

Total Counter is: 100
Newly Added Counter 100
Total Counter is: 800
Newly Added Counter 700

Property Wrapper

In Swift, property wrappers are used to add a layer between the code that manages how a property is going to be stored and the code that defines a property. Or we can say that property wrappers are used to encapsulate the property behaviour in a reusable manner. They are commonly used to add additional functionality to a property. The @propertyWrapper attribute is used to define a property wrapper.

Example

@propertyWrapper
struct Ten {
   private var num = 0
   var wrappedValue: Int {
      get { return num}
      set { num = min(newValue, 18) }
   }
}

struct Rectangle {
   @Ten var length : Int
   @Ten var height : Int
}

var obj = Rectangle()
print(obj.length)

obj.length = 11
print(obj.length)

Output

It will produce the following output −

0
11

Local and Global Variables

Local and global variables are declared for computing and observing the properties.

Local Variables Global Variables
Variables that are defined within a function, method, or closure context. Variables that are defined outside function, method, closure, or type context.
Used to store and retrieve values. Used to store and retrieve values.
Stored properties is used to get and set the values. Stored properties is used to get and set the values.
Computed properties are also used. Computed properties are also used.

Type Properties

As we know instance property always belongs to an instance of a specified type. So whenever we create a new instance it always contains a set of values for the properties and they are separated from another instance.

However, sometimes we want a property that belongs to itself not to any instance. So this problem is solved by the Type property. The type property is a special property that belongs to itself and will have only one copy, regardless of how many instances of that type are created. The stored type property can be a constant or variable whereas computed type properties are always variable.

Type properties are defined in the Type definition section with curly braces {} and the scope of the variables is also defined previously. For defining type properties for value types 'static' keyword is used and for class types 'class' keyword is used.

Syntax

struct Structname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // return an Int value here
   }
}

enum Enumname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // return an Int value here
   }
}

class Classname {
   class var computedTypeProperty: Int {
      // return an Int value here
   }
}

Querying and Setting Properties

Just like instance properties Type properties are queried and set with '.' Syntax just on the type alone instead of pointing to the instance.

Example

struct StudMarks {

   // Type properties
   static let markCount = 97
   static var totalCount = 0
   var InternalMarks: Int = 0 {
      didSet {
         if InternalMarks > StudMarks.markCount {
            InternalMarks = StudMarks.markCount
         }
         if InternalMarks > StudMarks.totalCount {
            StudMarks.totalCount = InternalMarks
         }
      }
   }
}

// Instances of structure
var stud1Mark1 = StudMarks()
var stud1Mark2 = StudMarks()

// Accessing property
stud1Mark1.InternalMarks = 98
print(stud1Mark1.InternalMarks) 

stud1Mark2.InternalMarks = 87
print(stud1Mark2.InternalMarks)

Output

It will produce the following output −

97
87
Advertisements