Skip to content

Classes, part 1

Informations presented on this page may be incomplete or outdated. You can find the most up-to-date version reading my book Learn Swift by examples. Beginner level

Prepared and tested with Xcode 8.3 and Swift 3.1

In this tutorial we cover the following topics


General notes about structures and classes in Swift

Both structures and classes in Swift can

  • define properties to store values;
  • define methods to provide functionality;
  • define initializesr to set up their initial state;
  • conform to protocols to provide standard functionality of a certain kind;
  • define subscripts to provide access to their values using subscript syntax;
  • be extended to expand their functionality beyond a defaut implementation.

Moreover, classes have some additional apapbilities that structures do not

  • inheritance;
  • we can check and interprete the type of a class instance at runtime;
  • reference counting allows more than one reference to a class instance;
  • deinitializers enable an instance of a class to free up any resorces it has assigned.

Another worth mention difference is that structures ale always copied when they are passed around in the code and to not use reference counting. Structure instances are always passed by value, and class instances are always passed by reference.


Objective-C vs. Swift difference
In Onjective-C's Foundation NSArray, NSDictionary, NSString are implemented as classes, not structures. This means that arrays, dictionaries and strings are always passed as a references, rather than as a copy.

In Swift Array, Dictionary and String are implemented as structures. This means that data of this type when are assigned to a new constant or variable, or when they are passed to a function or method, are copied.


Simple structures and classes definition

Properties initialization is Swift is a little bit tricky. For classes we cannot leave properties uninitialized, for example

is not allowed and cause and error: Class 'FooClass' has no initializers. Because for structures we have automatically generated memberwise initializer, we have to use it to initialize the member properties of new structure instances if they are not initialized explicitely. For classes we have to use explicite statement like in var integreVariableStoredPropertie = 0 or initializers (see further).

Notice that even though that instanceFooClass_2 is constant, we can modify its properties. We cannot do this with structures. Explanation of this is simple: first uses references (and this reference stays constant) while latter uses real values.


Properties


Computed properties

Classes, structures and enumerations can define computed properties. This type of properties do not actually store a value. Instead, they provide a getter (get) and an optional setter (set) to retrieve and set other properties and values indirectly. Sometimes we don't need to store explicitly (permanently) some value - for example it may be to expensive (taking into consideration memory usage) or this value may be computed based on other values.

To define computed property we use get and set keyword. In case we want to have a read only computed property we can skip the get keyword (and of course there is no set because this is read only property).


simpleProperty=3 computedProperty=6 computedPropertyReadOnly=9
simpleProperty=15 computedProperty=30 computedPropertyReadOnly=45


Setting a property with a closure or function


Lazy stored properties

Another new concept in Swift is a lazy stored property. A lazy stored property is a property whose initial value is not calculated until the first time it is used. Lazy properties may be useful when the initial value for a property is not known until after an instance's initizlization is complete, for example we may use it for time consuming initialization process. Lazy property must always be declared as a variable - constant properties must always have a value before initialization completes.

In the following code, we have to use init nad func- dont't worry about them now, take them as they are; we will discuss them in the next part of the material. First one is a special function called when an instance is created, second defines a function (an action) we can call on this instance (we can perform on this instance)


Init Action class
Do something for Action instance
Init LazyAction class
Do something for LazyAction instance


If a property marked as a lazy is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once.


Property observers

Property observers are really great things. They monitor to any changes in a property's value. Every time a property's value is set, even if the new value is not really new, observer is called. We can add property observer to any stored properties, except for lazy stored properties.

Thera are two observers.

  • First, willSet is called just before the value is stored. This observer gets new property value as a constant parameter with a default name of newValue. We can specify our own name if we don't like this one.
  • Second, didSet is called just after the new value is stored. This observer gets old (previous)) property value as a constant parameter with a default name of oldValue. We can specify our own name if we don't like this one.

When a default value is assigned to a stored property, or its initial value is set with an initializer, the value of that property is set directly, without calling any property observers.


firstPropertyToObserve is going to get new value of: 5
An old value of firstPropertyToObserve (3) has just been replaced by a new one
secondPropertyToObserve is going to get new value of: 9
An old value of secondPropertyToObserve (7) has just been replaced by a new one


Type properties

Type properties are properties related with particular type rather than particular instance of that type. They are like static variables or constants in C or Java.


44 66 66
444 666 666


Methods (instance and type methods)

  • Instance methods are functions which esence of existence is to provide some functionality related to the instance of a class. In other words, this type of functions works on particular instance of a class. So first we have to create on object and then we can perform some actions on it using instance methods. Instance methods have exactly the same syntax as functions.
  • Type methods, in contrast to instance methods, are functions which esence of existence is to provide some functionality related to the type itself rather than instance of a class. In other words, this type of functions works on a class. So we don't have to create any object of a class to use this class type methods.

As in many modern programming languages, we don't have to write self, which is used to refer to the current instance within its own methods, when it is not realy needed.


0
12
0
36

Notice that in the above example instead of static func we could also write class func as in the example below


func1
func2
func3

As we can see both seems to be the same. They seems to be, but they are not the same. Simplyfying, we can say that static is for static functions of structs and enums, and class for classes and protocols. Because classes, but not structs, can inherit from another class, class functions have other properties: they can be overridden by subclasses and they are dynamically dispatched.


func1
func2 in ClassB
func3


myOtherClass
myClass


Mutating methods

For structures and enumeration we can also implement mutating methods which allows to modify the properties of value type (structures and enumerations but not classes which are reference type) from within its instance methods. By default, the properties of a value type cannot be modified from within its instance methods.


Item Test string has priority 1
Again new text


Subscripts

This ia another feature we can find in Swift - maybe not really necessary, but with it our life can be simpler. We can define subscripts for structures, classes and enumeration. Typically subscripts are used for arrays and dictionaries and are denoted with square brackets [ and ]. We can use this syntax to have more natural access to some of our properties.


First subscript, set, 2=3
3
Second subscript, set, 2 = new string
new string
Third subscript, set, 2222 + SeCrEt = true
true
Fourth subscript, set, 3333 + PaSSworD = Secret message
Secret message
First subscript, get, 2
3
Second subscript, get, 2
new string
Third subscript, get, 2222 + SeCrEt
true
Fourth subscript, get, 3333 + PaSSworD
Secret message


Inheritance

I hope that you have an understanding what is an inheritance, so I'll give only syntax information.

We use override keyword to mark method, property or subscript as overriden. Superclass's method, property or subscript is accessed with super keyword. To prevent method, property or subscript from being overriden we mark it with final modifier. We can mark entire class as final preventing them to be subclassing.


subClass: init
baseClass: init
subClass: doSomething
baseClass: notForSubclassing
baseClass: anotherOneFunction
5 text
subClass: callMethodFromSuperClass
baseClass: notForSubclassing