Classes and Structures in Swift

Classes and Structures in Swift

Swift language introduced a significant improvement of structures, and thus in many cases made them an interesting alternative to classes. Quite many functionalities of classes and structures are similar, but there are a few differences and because of them it is a good idea to consider which of these forms is more useful in what situation.

Common features of classes and structures

  • properties storing specific values,
  • defining methods in order to provide functionalities,
  • defining subscripts through which you can gain access to a selected value,
  • initializers, with which we set up initial state,
  • extending functionalities beyond a default implementation,
  • can adjust to protocols.

The most important differences

  • classes support inheritance, whereas structures don’t,
  • for a class we can define deinitializers,
  • classes are a type passed by a reference, whereas structures are passed by a value.

Creating an instance of both class and structure is very similar. It only differs in the key word – class or struct. We can access their values in the same way. We will however notice the difference when creating an instance. For a structure, based on all its properties, an memberwise initializer will be automatically created. For example, for the structure:

struct Coordinates {
	var x : Float
	var y : Float
	var z : Float
}

there will be created a following initializer:

var myCoordinates = Coordinates(x: , y: , z: )

for which we need to fill the values of x, y, z.

Due to the fact that a class is a reference type, and a structure a value type, they will behave differently when an already created object will be assigned to a new instance and when an operation on this instance will be executed. For example, for the above-mentioned structure:

var myCoordinates = Coordinates(x: 0 , y: 0, z: 0)
var anotherCoordinates = myCoordinates
anotherCoordinates.x = 22

After execution of these operations, the value of x is still 0 for myCoordinates, whereas for anotherCoordinates it is 22. This is due to the fact that at the time of the assignment of myCoordinates to anotherCoordinates there was passed not a reference to the object, but its copy. At the time of execution of corresponding operations on class instances, the value of the x variable would be 22 in both cases.

If we use an instance of a structure as a method parameter, we also sent a copy, therefore changes made during the execution of the method will be stored only locally in its scope. If we want changes to be used in our instance globally, we need to mark the method parameter as inout.

With this tag, the changes performed during the execution of the function will be assigned to the parameters passed to the function by a value.

func changeCoordinates(inout coordinates: Coordinates) {
	coordinates.x = 88
	coordinates.y = 100
}

changeCoordinates(&myCoordinates)

After performing such actions values of x and y in myCoordinates instance will be 88 and 100. It should be noted that in this case, contrary to standard passing of function parameters, a parameter myCoordinates is preceded with &.

Another notable difference is in results of defining an instance of a class or a structure as a constant. In case of a class, after creating an object constant we can’t change the object to which it refers, but we can edit the properties of the object assigned to this constant. For a structure also properties of an object are unchangeable. This is illustrated by the following example:

  • for class:
After performing such actions values of x and y in myCoordinates instance will be 88 and 100. It should be noted that in this case, contrary to standard passing of function parameters, a parameter myCoordinates is preceded with &.

Another notable difference is in results of defining an instance of a class or a structure as a constant. In case of a class, after creating an object constant we can't change the object to which it refers, but we can edit the properties of the object assigned to this constant. For a structure also properties of an object are unchangeable. This is illustrated by the following example:

for class
  • for structure:
let myCoordinates = Coordinates(x: 0 , y: 0, z: 0)
var anotherCoordinates = myCoordinates
myCoordinates = anotherCoordinates  // error
myCoordinates.x = 22 // also error

Structures also introduce a security related to methods that alter properties of that structure. Adding a method:

func increaseByTwo() {
	self.x = self.x + 2
}

to the discussed structure is not allowed, as it changes the self parameter. To enable a method to perform such operations we should add to it the keyword “mutating”.

mutating func increaseByTwo() {
	self.x = self.x + 2
}

Now, compiler will no longer consider this method an error.

Structures or classes?

Looking at various possibilities offered by structures and classes a question arises of when to use a structure and when to choose a class. Apple’s documentation mentions that the primary purpose of a structure is to store relatively simple values. At the time of passing an instance of a structure, these values should be the values which we want to copy and not give references of. When choosing we should also remember about the fact that structures do not support inheritance.

As good examples of using a structure there were listed:

  • dimensions of geometric shapes,
  • all sorts of coordinates.

If you encounter a suitable candidate for a structure, you should use it, as for objects containing only a few simple values its performance is better than performance of a class.

 

You should also mind that in Swift arrays and dictionaries are also structures. Due to that, at the moment of assigning one instance of an array to another array data is copied, and as a result a change in one array is not reflected in the other. In Objective-C to get such behavior we had to intentionally create an array using the copy method.

Learn more

iOS Small Talks: PubNub – Solution for the Real-time Communication

We encounter applications running in real time pretty much everywhere. Any chat or a game uses this technology. Creating communication that is based on the assumption that what is happening in reality should be immediately reflected in the application, is unfortunately neither easy nor cheap. However for small applications we don’t need to spend huge money on dedicated infrastructure. PubNub can help us.

Read more

Bitrise Tests Made Easier: Update JIRA Issues with Build Number and Forget About Delays in QA Testing

When you trigger Bitrise build with changes and forget to tell QA specialists some essential information, there are two likely scenarios. You waste time waiting for the update from the tester, only you don’t know it’s never coming. Or you get so many questions about builds that you can’t keep up. Sounds familiar? If so, let us tell you about the JIRA issue update that keeps workflow in order.

Read more

How to Send iOS Notifications in Different Languages? Guide to Dynamic Localization

The best way to set a connection between a user, provider, and an app? System notifications. They allow users to get the latest news in no time. This solution is easy to implement in apps dedicated to one market. But it gets complicated when the messages must be displayed in many languages. In such cases, the dynamic localization of remote notifications can be a real game-changer.

Read more

Project estimation

Let us know what product you want to build and how we can help you.

Why choose us?

Logo Mobile Trends Awards

Mobile Trends Awards 2017

Nomination in
M-COMMERCE category

Logo Legalni bukmacherzy

Legal Bookmakers Award 2019

Best Mobile App

Mobile Trends Awards logo

Mobile Trends Awards 2020

Nomination in SPORT & RECREATION category

17

client reviews

Clutch logo