Mastering macOS Programming
上QQ阅读APP看书,第一时间看更新

Classes

If we take a struct instance and copy it, we have two completely separate entities; changing one will have no effect on the other. This behavior of struct data types can be a real boon to code safety-unexpected values in shared data structures (or the complete lack of a value) are possibly the most common source of bugs in object-oriented programming. Using struct, each function in your code gets its own copy, to deal with as it sees fit, without needing to take into account what some other function somewhere might do to it, or need from it.

But as you probably know already, we very often need to pass a reference to one particular unique instance of structured data. Most languages call this a class, and Swift is no different.

Let's take a look at a very basic class:

class SteamTrain 
{
let locName: String?
var drivers: [String]
var numberOfCarriages: Int

init(locName: String,
drivers: [String],
numberOfCarriages: Int,
currentStation: String?)
{
self.locName = locName
self.drivers = drivers
self.numberOfCarriages = numberOfCarriages
}

func add(newCarriages: Int)
{
numberOfCarriages += newCarriages
}
}

The similarities to struct are clear enough, so what of the differences? Firstly, we notice that there is no automatic memberwise initializer provided, we have had to write one explicitly. Within this initializer, we need to refer to self to set the class's properties from the arguments supplied to the initializer.

In contrast to Objective C and many other languages, the class need not declare a superclass (or base class), although we will look at subclassing and inheritance in Chapter 5, Advanced Swift, in which we do provide a superclass.

The method add(newCarriages: Int) is used to increase the number of carriages by modifying a class variable property.

Creating an instance of the class is similar to doing so with a struct:

let oldLoc = SteamTrain(locName: "Puffing Billy", 
drivers: ["Harpo", "Groucho"],
numberOfCarriages: 1,
currentStation: nil)

We access the properties in the same way as those of a struct:

print(oldLoc.locName) 

But, we declared oldLoc to be constant with let. Can we then change its variable properties? Because it is a class type, we can:

oldLoc.drivers.append("Marco") 

That is, as long as the property is declared to be variable. We have made the SteamTrainname property immutable, and so the following line of code would produce an error:

oldLoc locName = "Rocket" 

If we decided that a SteamTrain name might change, we'd have to make it mutable. But who renames a steam locomotive?

Since class objects are passed by reference, it is possible to have two variables or constants that point to the same instance:

let mysteryLoc = oldLoc 

We can test for this with the === operator, or its negation, !==:

mysteryLoc === oldLoc 

This operator means is the same instance as. This is different to the equality == operator, which you have to define yourself for any given class (see Chapter 5, Advanced Swift), according to whichever criteria are appropriate for the class in question.