In most traditional object-oriented programming languages we create classes, which are reference types, as blueprints for our objects. In Swift, unlike other object-oriented languages, structures have much of the same functionality as classes; however, they are a value type. Apple has said that we should prefer value types, such as structures, to reference types, but what are the actual advantages? Swift actually has a number of type choices that we can use and, in this chapter, we will look at each of these types to see the advantages and disadvantages of each. Knowing how and when to use each type is important to properly implement protocol-oriented programming in your projects.
In this chapter, you will learn:
Swift classifies types as either named or compound types. A named type is a type that can be given a name when it is defined. These named types include classes, structures, enumerations, and protocols. In addition to user-defined named types, Swift also defines many commonly used named types within the Swift standard library, including arrays, sets, and dictionaries.
Many of the data types that we would normally consider Primitive types in other languages are actually named types in Swift and are implemented in the Swift standard library using structures. These include types that represent numbers, strings, characters, and Boolean values. Since these types are implemented as named types, we are able to extend their behavior using extensions as we would with any other named type. As we will see in this chapter and the future ones, the ability to extend a named type, including types that would traditionally be considered as primitive types and protocols, is an extremely powerful feature of the Swift language and is one of the pillars of protocol-oriented programming.
A compound type is a type that is not given a name when it is defined. In Swift, we have two named types: function types and tuple types. Function types represent closures, functions, and methods, while tuple types are a comma-separated list that are enclosed in parentheses.
We are able to use the typealias declaration to give an alias to our compound types. This allows us to use the alias name instead of the type itself within our code.
There are also two categories of types: reference types and value types. When we pass an instance of a reference type, we are passing a reference to the original instance, which means that the two references are sharing the same instance. Classes are reference types. When we pass an instance of a value type, we are passing a new copy of the instance, which means that each instance is getting a unique copy. Value types include structures, enumerations, and tuples.
Every type in Swift will be either a named or compound type, and they will also be either a reference or value type, except in the case of protocols. Since we are unable to create an instance of a protocol, it is neither a reference nor a value type. Sounds a bit confusing? It really isn't. As we look at all of our type choices and how we can use them, we will see how easy this is to understand.
Now, let's begin looking at the type choices that we have in Swift. We will begin by looking at the backbone of object-oriented programming: the class.
In object-oriented programming, we cannot create an object without a blueprint that tells the application what properties and methods to expect from the object. In most object-oriented languages, this blueprint comes in the form of a class. A class is a construct that allows us to encapsulate the properties, methods, and initializers of an object into a single type. Classes can also include other items, such as subscripts; however, we are going to focus on the basic items that make up classes not only in Swift but in other languages as well.
Let's look at how we would use the class in Swift. The following code shows how we defined the Drink
class in Chapter 1, Object-Oriented and Protocol-Oriented Programming:
class Drink { var volume: Double var caffeine: Double var temperature: Double var drinkSize: DrinkSize var description: String init(volume: Double, caffeine: Double, temperature: Double, drinkSize: DrinkSize) { self.volume = volume self.caffeine = caffeine self.temperature = temperature self.description = "Drink base class" self.drinkSize = drinkSize } func drinking(amount: Double) { volume -= amount } func temperatureChange(change: Double) { temperature += change } }
An instance of a class is typically called an object; however, in Swift, structures and classes have much of the same functionalities therefore, we will use the term instance when referring to instances of either type. We will create an instance of the Drink
class as follows:
var myDrink = Drink(volume: 23.5, caffeine: 280, temperature: 38.2, drinkSize: DrinkSize.Can24)
Anyone who has used object-oriented programming in the past is probably familiar with the class type. It has been the backbone of object-oriented programming since its inception.
When we create instances of the class, it is named therefore the class is a named type. The class type is also a reference type.
The next type we are going to look at is arguably the most important type in the Swift language: the structure.