All about Properties in swift

just an illustration from somewhere :p

First , let me talk about a property . Suppose if we need to change or access an iVar in your class using an object of your class, then there should be getter and setter methods assigned to the iVar. A property is used mainly when other objects need to change or access the ivars in your object, without manually defining getters and setters, or using @property (in objective - c).

In objective-c, @property declares a property in your class header. Here is an example:

@property (nonatomic, retain) NSString *myString;

@synthesize creates your setter and getter for your property (accessor methods). Without synthesize you have to write your own setter and getter implemention, like getMyString or setMyString (capitalize the first character of your property).

So, the above property declaration is equivalent to:

- (NSString*)myString {}
- (void)setMyString:(NSString*)newValue {}

Properties can be further classified into Stored properties and Computed properties.

Stored Property vs Computed property

Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value.

►Computed properties are provided by classes, structures, and enumerations.

►Stored properties are provided only by classes and structures.

In its simplest form, 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 stored properties (introduced by the varkeyword) or constant stored properties (introduced by the let keyword).

The example below defines a structure called FixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created:

struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// the range represents integer values 0, 1, and 2
rangeOfThreeItems.firstValue = 6
// the range now represents integer values 6, 7, and 8

Instances of FixedLengthRange have a variable stored property called firstValue and a constant stored property called length. In the example above, length is initialized when the new range is created and cannot be changed thereafter, because it is a constant property.


Stored Properties of Constant Structure Instances

If you create an instance of a structure and assign that instance to a constant, you cannot modify the instance’s properties, even if they were declared as variable properties:

let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// this range represents integer values 0, 1, 2, and 3
rangeOfFourItems.firstValue = 6
// this will report an error, even though firstValue is a variable property

Because rangeOfFourItems is declared as a constant (with the let keyword), it is not possible to change its firstValue property, even though firstValue is a variable property.

NOTE: This behavior is due to structures being value types. When an instance of a value type is marked as a constant, so are all of its properties.
The same is not true for classes, which are reference types. If you assign an instance of a reference type to a 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 indicate a lazy stored property by writing the lazy modifier before its declaration.

Please refer my article on lazy var : lazy var in ios swift

Computed Properties

In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.

If you define get { } inside the property declaration, it makes that property to a computed property. And it cannot have initial value as when you access the property, it will always call get{} function declared in property.

We can skip the associated get and set keyword and their curly brackets if we do not have to set a value to the variable. Computed property with a getter but no setter is known as a read-only computed property. Check the below example:

var a:String{
return “a”
}
print(a) // prints a

The above declaration is same as:

var a:String{
get {
return “a”
}
}

►We can use an optional setter to the computed variable which accepts a newValue as parameter.

class Alphabets {
var _a:String?
var a:String {
get {
return _a ?? “not set”
}
set(newVal) { //you can use any name for the passed parameter.Default is newValue
_a = newVal
}
}
}
/*----------------------------------------------------*/
let alphabet1 = Alphabets()
alphabet1.a = “a”
print(alphabet1.a) // prints a

If a computed property’s setter does not define a name for the new value to be set, a default name of newValue is used. Here’s an alternative version of the Alphabets class, which takes advantage of this shorthand notation:

class Alphabets {
var _a:String?
var a:String {
get {
return _a ?? “not set”
}
set { // no values passed..
_a = newValue // default value name is newValue
}
}
}
/* — — — — — — — — — — — — — — — — — */
let alphabet1 = Alphabets()
alphabet1.a = “a”
print(alphabet1.a) // prints a

Well, what happens if you try to set a computed property in its own setter?

You cannot do that. It will call the same setter method again and again and it will create an endless loop. The app may crash due to a memory overrun.

By definition, a computed property is one whose value you cannot set because, well, it’s computed. It has no independent existence. The purpose of the setter in a computed property is not to set the value of the property but to set the values of other properties, from which the computed property is computed.

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 observers to any stored properties you define, except for lazy stored properties. We can add property observers to ‘inherited’ property by method ‘overriding’.

You have the option to define either or both of these observers on a property:

  • willSet is called just before the value is stored.
  • didSet is called immediately after the new value is stored.

If you implement a willSet observer, it’s passed the new property value as a constant parameter. You can specify a name for this parameter as part of your willSet implementation. If you don’t write the parameter name and parentheses within your implementation, the parameter is made available with a default parameter name of newValue.

Similarly, if you implement a didSet observer, it’s passed a constant parameter containing the old property value. You can name the parameter or use the default parameter name of oldValue.

Here is an example given by apple to explain the flow:

The willSet and didSet observers for totalSteps are called whenever the property is assigned a new value. This is true even if the new value is the same as the current value.

Note:Computed property should be a variable.
let b:Int {
return 4 //error. error: ‘let’ declarations cannot be computed properties
}

Type Properties :

Instance properties are properties that belong to an instance of a particular type. Every time you create a new instance of that type, it has its own set of property values, separate from any other instance.

You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties.

In Swift, type properties are written as part of the type’s definition, within the type’s outer curly braces, and each type property is explicitly scoped to the type it supports.

You define type properties with the static keyword. For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation.

static and class both associate a method with a class, rather than an instance of a class. The difference is that subclasses can override class methods; they cannot override static methods.

The example below shows the syntax for type properties:

In the above example, we tried to override a static func in the subclass Enemy but got an error like : error: cannot override static method .

If you enjoyed reading this post and found it useful, please share and recommend it so others can find it 💚💚💚💚💚💚 !!!!

Thanks!!