Properties In Swift

Stored Properties

Properties associate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance.
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.

struct Size {
 var width: Int 
 let height: Int 
}
var size1 = Size(width: 10, height: 35)
size1.width = 6

In the example above, height is initialized when the new size is created. This is a constant property, and it cannot be changed once initialized.
When creating an instance of a structure, if you assign an instance of a structure to a constant, the instance‘s properties cannot be modified, even if they were declared as variable properties.

Lazy Stored Properties

A lazy stored property’s initial value is not calculated until the first time it is used.

class DataManager {
 lazy var importer = DataImporter()
 var data = [String]()
}

Lazy properties are useful when a property’s initial value is dependent on outside factors, the values of which are not known until after an instance‘s initialization is complete; or when the initial value for a property requires complex or computationally expensive setup that should not be performed unless or until it is needed.
You must always declare a lazy property as a variable, using the var keyword, because its initial value might not be retrieved until after the completion of instance initialization. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.

Computed Properties

Rather than storing a value, a computed property provides a getter and, optionally, a setter, which indirectly retrieve and set other properties and values, respectively.

struct Point {
 var x = 0.0, y = 0.0
}
struct Shape {
 var origin = Point() 
 var center: Point {
  get {
   return Point(x: origin.x/2 , y: origin.y/2)
  }
  set(newCenter) {
   origin.x = newCenter.x/2
   origin.y = newCenter.y/2
  }
 }
}

The Shape structure defines a custom getter and setter for a computed variable called center. The center property is then accessed through dot syntax, which causes the getter for center to be called to retrieve the current property value. Rather than returning an existing value, the getter actually calculates and returns a new point that represents the center of the shape.

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.
Below is an alternative version of the Rect structure, which takes advantage of this shorthand notation:

struct Point {
 var x = 0.0, y = 0.0
}
struct Shape {
 var origin = Point() 
 var center: Point {
  get {
   return Point(x: origin.x/2, y: origin.y/2)
  }
  set {
   origin.x = newValue.x/2
   origin.y = newValue.y/2
  }
 }
}

A computed property with a getter but no setter is known as a read-only computed property. It always returns a value, and can be accessed through dot syntax. However, that value cannot be altered.

Property Observers

Property observers detect 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.
Property observers can be added to any defined stored properties, with the exception of lazy stored properties.
You have the option of defining either or both of the following observers of a property:
willSet is called just before the value is stored.
didSet is called immediately after the new value is stored.

The example below defines a new class called StepCounter, which tracks the total number of steps that a person takes while walking.

class StepCounter {
 var totalSteps: Int = 0 {
  willSet(newSteps) {
   print("About to set totalSteps to \(newSteps)")
  }
  didSet {
   if totalSteps > oldValue  {
   print("Added \(totalSteps - oldValue) steps")
   }
  }
 }
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 50
// About to set totalSteps to 50
// Added 50 steps
stepCounter.totalSteps = 150
// About to set totalSteps to 150
// Added 100 steps
stepCounter.totalSteps = 420
// About to set totalSteps to 420
// Added 270 steps

The StepCounter class declares a totalSteps property of type Int, with willSet and didSet observers.
The willSet and didSet observers for totalSteps are called whenever the property is assigned a new value.
The willSet observer uses a custom parameter name of newSteps for the upcoming new value.

The didSet observer is called after the value of totalSteps is updated. It compares the new value of totalSteps against the old value. The didSet observer does not provide a custom parameter name for the old value; the default name of oldValue is used, instead.
Similarly, newValue could be used for the willSet observer, if no parameter name was defined.
If you assign a value to a property within its own didSet observer, the new assigned value will replace the one that was just set.

Type Properties

Type properties are useful when defining values that are universal to all instances of a particular type, such as a constant property used in all instances, or a variable property that stores a global value to all instances of that type. Stored type properties can be variables or constants. You define type properties with the static keyword:

class SomeClass {
 static var storedProp = "Some value."
 static var computedProp: Int {
   return 42
 }
}

Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type:

print(SomeClass.storedProp) 

Unlike stored instance properties, you must always give stored type properties a default value. This is because the type itself does not have an initializer that can assign a value to a stored type property at initialization time.

Advertisements
Properties In Swift

All about Properties in swift

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 firstValueis 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 Enemybut 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!!

All about Properties in swift