Open In App

Swift – Properties and its Different Types

Last Updated : 28 Mar, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

In Swift, properties are associated values that are stored in a class instance. OR we can say properties are the associate values with structure, class, or enumeration. There are two kinds of properties: stored properties and computed properties. Stored properties are properties that are stored in the class’s instance. Stored properties store constant and variable values. Computed properties are for creating custom get and set methods for stored properties. Computed properties are provided by classes, structures, and enumerations to provide custom behavior for properties. Stored and computed properties are usually associated with a particular type but can be associated with any type. These properties are called type properties. We can use type properties to provide default values for properties of a particular type.

Stored Properties 

A stored property is a property whose value is stored as part of the instance of a particular type. Stored properties can be either variable or constant. We can use var to create a variable stored property, and let to create a constant stored property.

1. For variable stored properties: Here we use var to create a variable stored property. Suppose we have a structure named Person, which contains a stored property named the name of type String. So we have created a Person instance and assigned a value to the name property. The name property is a stored property, so it is stored in the instance of the Person structure.

Swift




// Swift program for variable stored properties
 
// Creating structure
struct Person
{
 
    // Stored property
    var name: String
}
 
// Creating a Person instance
let person = Person(name: "Geek2Geeks")
 
// Prints "The person's name is Geek2Geeks"
print("The person's name is \(person.name)")


Output:

The person's name is Geek2Geeks

2. For constant stored properties: Here we use let to create a constant stored property. Suppose we have another structure named Employee, which contains a constant stored property named age of type Int. And we have also created a constant stored property named the name of type String.

Swift




// Swift program for constant stored properties
 
// Structure
struct Employee
{
 
    // Constant stored property
    let age: Int
     
    // Constant stored property
    let name: String
}
 
// Creating an Employee instance
let employee = Employee(age: 30, name: "Geek2Geeks")
 
// Prints "The employee's name is Geek2Geeks"
print("The employee's name is \(employee.name)")
 
// Prints "The employee's age is 30"
print("The employee's age is \(employee.age)")


Output:

The employee's name is Geek2Geeks
The employee's age is 30

Here, we have created a constant Employee instance and assigned a value to the age and name properties. The age property is a constant stored property, so it is stored in the instance of the Employee structure. The name property is a constant stored property, so it is stored in the instance of the Employee structure.

Lazy Stored Properties

Lazy stored properties are a way to defer the initialization of a property until it is first used. This is useful for expensive properties, such as an NSURL object, or a large collection, such as a large dictionary or array. Lazy properties are also useful for creating properties whose initial value depends on another property, such as the current date or a name for a file. You can create a lazy property by writing lazy modifier before its declaration. It is also useful when the initial value of the property requires a complex setup.

Example:

Swift




// Swift program for lazy Property
 
// Class which contain lazy property
class GFG
{
    var Cname : String?
     
    // lazy property
    lazy var course : String = {[weak self] in
         
        guard let x = self else { return "Doesnot warp itself"}
        guard let y = x.Cname else { return "Course not found" }
         
        return "Course is: \(y)"
    }()
     
    init(Cname: String)
    {
        self.Cname = Cname
    }
}
 
// Assigning value
var y = GFG(Cname: "Swift")
 
// Displaying the result
print(y.course)


Output:

Course is: Swift

Explanation: In the above example we have created a class named GFG. This class contains a lazy property named course. This property will return a string that contains the name of the course. In this property, we use weak self to remove reference cycle and also use guard let for optional unwrapping.

Computed Properties 

 Computed properties are provided by classes, structures, and enumerations to provide custom behavior for properties. They are similar to methods, but they are written as part of the type itself rather than as part of an instance. They do not store values instead they use getter and setters to retrieve and set property and its values indirectly. Computed property can be assigned to a lazy var property and a computed property which have to get and set cannot be defined as a constant let.

Example:

Swift




// Swift program for Computed Properties
 
// Structure
struct rectangle
{
    var len: Double
    var width: Double
     
    // Computed property
    var perimeter: Double{
     
        // Getter
        get{
            return (2 * (len + width))
        }
         
        // Setter
        set(newperimeter)
        {
            len = (newperimeter - width)/2
        }
    }
}
 
var ob = rectangle(len: 10, width: 5)
 
// Accessing the property
print("Perimeter: ", ob.perimeter)
 
// Setting property with new value
ob.perimeter = 40
 
// Accessing the property
print("Length: ", ob.len)


Output:

Perimeter:  30.0
Length:  17.5

Explanation: The above example defines a structure called a rectangle, which contains one property named perimeter. The perimeter is a computed property that contains getter and setter. In this property, we find the perimeter of the rectangle and the new length by setting the value of the perimeter.

Read-Only Computed Properties

read-only computed property is a computed property that is present with getter only. It doesn’t contain a setter. This property always returns a value and can be accessed by using dot syntax. To declare a read-only computed property simply remove the get keyword and its braces.

Example:

Swift




// Swift program for read-only computed property
 
// Structure to find the volume of Cuboid
struct CuboidVolume {
   
    var w = 0.0, h = 0.0, d = 0.0
     
    // Reao only computed property
    var Cvolume: Double {
       
        return w * h * d
    }
}
 
// Assigning values
let vol = CuboidVolume(w: 4.0, h: 4.0, d: 4.0)
 
// Accessing read only computed property
print("The volume is \(vol.Cvolume)")


Output:

The volume is 64.0

Explanation: In this example, we have a class CuboidVolume which has a property named Cvolume. This property is a read-only computed property. The Cvolume property is a getter only and does not have a setter. The Cvolume property is defined as a read-only computed property because it does not need to store a value. It does not need to be stored in the CuboidVolume structure’s instance, because it is only used for computing the volume of the cuboid.

Property Observers 

These are methods that are called automatically by the system when a property’s value is set. Property observers are called after the property’s value is set, regardless of whether the new value is different from the property’s current value. We can add property observers to any stored or computed property, and observe changes to that property’s value. For a stored property, the observer is called when the property is assigned to a new value. For a computed property, the observer is called when the property is read or written. We can use willSet and didSet to observe changes to a property’s value.

Example:

Swift




// Swift program for property observers
 
// Class to count the total cat step
class Counter
{
    var totalCatSteps: Int = 0 {
     
        // Property observer
        willSet(newTotalCatSteps)
        {
            print("Setting cat totalSteps: \(newTotalCatSteps)")
        }
         
        // Property observer
        didSet {
            if totalCatSteps > oldValue  {
                print("Added new steps: \(totalCatSteps - oldValue)")
            }
        }
    }
}
 
// Creating class object
let CatStep = Counter()
 
// About to set CatStep to 105
// Added 105 steps
CatStep.totalCatSteps = 105
 
 
// About to set CatStep to 250
// Added 135 steps
CatStep.totalCatSteps = 240
 
// About to set CatStep to 370
// Added 130 steps
CatStep.totalCatSteps = 370


Output:

Setting cat totalSteps: 105
Added new steps: 105
Setting cat totalSteps: 240
Added new steps: 135
Setting cat totalSteps: 370
Added new steps: 130

Explanation: In the above example, we have a Counter class that contains the willSet and didSet observers and they are called when a stored property’s value is set. The willSet observer is called before the value is stored. The didSet observer is called after the value is stored. Here, the willSet observer prints a message before the value is stored, and the didSet observer prints a message after the value is stored. The didSet observer prints a message if the new value is greater than the property’s previous value.

Property wrappers 

A property wrapper is a property that provides additional functionality on top of another property. A property wrapper is a property that is a subclass of the property it wraps. The property wrapper class is a subclass of the property it wraps. It adds additional functionality to the property it wraps. Or in other words, it adds a separation layer between the code that manages how a property stored and the code which defines the property. To use a property wrapper we have to write a management code when we define a wrapper and then we can reuse the management code by applying multiple properties to it.

We can define a property wrapper by creating structure, enumeration, or a class that defines wrappedValue property. To apply a wrapper to property simply write the wrapper’s name before the property attribute.

Syntax:

@propertyWrapper

struct Wrapper<T> {

   var wrappedValue: T

   init(wrappedValue: T) {

       self.wrappedValue = wrappedValue

   }

}

Here, Wrapper is a property wrapper that wraps a value of type T. The Wrapper class is a subclass of the property it wraps. The Wrapper class overrides the property wrapper’s behavior, such as by overriding the property wrapper’s setter.

Type Properties

Whenever we create a new instance of a class, we can set the properties of that instance. These instances have their own properties and these are called instance properties. So if we want to create multiple instances of a class, we can set the properties of each instance individually. But it would not be a good practice to set the properties of each instance individually. Then comes type properties to the rescue. Type properties are shared among all instances of a class. Only one copy of the properties is created for all the instances of a type we create.

Type properties are created using the static keyword. So we can access the properties of a type using the class name. But we cannot access the properties of an instance using the instance name.

Syntax:

    class MyClass { // class declaration

       static var typeProperty = “Some value” // type property

   }

   MyClass.typeProperty // type property access

   MyClass.typeProperty = “Some other value” /// type property assignment

Here, we have created a type property called typeProperty. The MyClass class has a static property called typeProperty. It can have any value. MyClass.typeProperty is a type property. It is a shared property. It is accessible using the class name.

Example:

Swift




// Swift program for type property
 
// Ios is a type
struct Ios
{
 
    // Version is a type property
    static var version = "iOS 10"
     
    // getVersion is a type method
    static func getVersion()
    {
     
        // Printing the version
        print(version)
    }
}
 
// Printing the version
Ios.getVersion()
 
// Printing the version
print(Ios.version)


Output:

   iOS 10
   iOS 10

Explanation: We have two iOs objects. One is created using the struct keyword and the other is created using the class keyword. Here is a simple example using type properties. The Ios struct has a static property called version. It can have any value. Ios.version is a type property. It is a shared property. The static function getVersion() is a static function. It will be called using the class name. The body of this function will be executed only once and the value of the version will be displayed. We have called the getVersion() function using the class name Ios. This is because the getVersion() function is a static function. It is called using the class name. The print function is used to display the value of the version.

Querying and Setting Type Properties 

Querying is used to get the value of a type property. The setting is used to set the value of a type property. Type properties are queried and set using the class name. We can use dot syntax to query and set type properties.

Example:

Swift




// Swift program to Querying and Setting Type Properties
 
// Ios is a type
struct Ios
{
    static var version = "iOS 10"
     
    // Version is a type property
    static var apilevel: Int{
        return 10
    }
}
 
// Querying
// Printing the version
print(Ios.version)
 
// Setting
// Setting the version
Ios.version = "iOS 11"
 
// Printing the version
print(Ios.version)
 
// Printing the apilevel
print(Ios.apilevel)


Output:

iOS 10
iOS 11
10

Explanation: Here what we are doing is we are creating a struct called Ios. Ios has two types of properties. One is called version. It can have any value. The other is called apilevel. It can have any value. The apilevel is a computed property. It is computed because it is dependent on the value of the version. We are querying the value of the version using the class name Ios. The print function is used to display the value of the version. similarly, we are setting the value of the version using the class name Ios also. The print function is used to display the value of the version.

Global and Local Variables

In general, variables are local to a function. But there are some exceptions. Global variables are variables that are defined outside of any function. They are accessible throughout the entire program. They are called global variables. The local variables are those variables that are defined inside a function. In Swift, we can also declare computed variables. computed variables calculate their value on the fly. That means that the value of the variable is calculated every time it is accessed. They are called lazy variables.

Example:

Swift




// Swift program to demonstrate the use of global and local variable
 
// Creating global variable
var globalVariable = "This is Global Variable"
 
func geeksforgeeks()
{
 
    // Creating local variable
    var localVariable = "This is Local Variable"
 
    print("Global Variable: \(globalVariable)")
    print("Local Variable: \(localVariable)")
}
 
// Calling the geeksforgeeks function
geeksforgeeks()
 
// Printing the global variable
print(globalVariable)


Output:

Global Variable: This is Global Variable
Local Variable: This is Local Variable
This is Global Variable

Explanation: Here, we have created a global variable called globalVariable. The globalVariable is a global variable. It is accessible throughout the entire program. The local variable is called the local variable. The local variable is a local variable. It is accessible only inside the geeksforgeeks function.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads