Classes and structures

Classes and structures (also known as structs) are files that contain properties and methods. You use these properties and methods to add functionality. You have been working with structs since Chapter 1, Getting Familiar with Xcode. Strings, Ints, Bools, Arrays, Dictionaries, and Sets are all structs.

Earlier in the book, we created functions. As noted in Chapter 6, Starting the UI Setup, a method is a function that lives inside a class or struct.

Classes and structs are very similar; however, Swift handles each of them a bit differently. To get a better understanding of how classes and structs work, we create a new Playground project. Working in the Playground gives us the ability to learn how to create custom classes and structs and to gain an understanding of each of their positives and negatives.

Since we already have a project created, we can actually add a playground directly into our project. Right-click in the Project Navigator and create a new group called Playgrounds. When you are done, you should see the following:

Next, right-click on the Playgrounds folder, go to New File, and do the following:  

  1. Scroll to the bottom of the template screen, select a Blank playground, and hit Next.
  2. In the options screen that appears, name your new Playground FunctionsStructs, and make sure that your Platform is set to iOS. Hit Next and then Create. Now, let's delete everything inside your new Playground and toggle on the Debug Panel, using either the toggle button or command + shift + Y.

In your empty Playground, add the following:

class Cat {
}

struct Dog {
}

We just created our first class and struct and defined two new custom data types (known as Swift types), Cat and Dog. Since we have not yet given the class or struct a property (such as a name) or created an instance of either Cat or Dog, you see nothing in the Results or Debug Panels.

When you create classes and structs, it is  best practice to start with a capital letter. Also, you must have different names for your class and your struct. Otherwise, you will get an error. Even though one is a class and the other is a struct, each of them needs a distinct name.

Now, we need to give names to our Cat class and our Dog struct. Therefore, let's give them both a property, called name:

class Cat {
var name:String?
}

struct Dog {
var name:String?
}

If you cannot set a property when it is created, then it is recommended that you set that property to an optional using the question mark (?). Using optional protects your code from trying to access the name if you never set it. You can also set your variable as an optional unwrapped. For example, you can also do the following:

var name:String!

With both Cat and Dog now having a property called name, let's create an instance of each of them:

let yellowCat = Cat()
yellowCat.name = "Whiskers"
print(yellowCat.name as Any)

var yellowDog = Dog()
yellowDog.name = "Bruno"
print(yellowDog.name as Any)

So far, everything on the surface looks the same. We created both a Cat and a Dog and gave them each names. However, let's say Whiskers runs away and, a few weeks later, finds a home with a new family, who decide to change his name to Smokey. After Whiskers runs away, Bruno becomes lonely and decides to find him, but also gets lost. Bruno finds a new home as well, and this new family decides to name him Max.

In Playgrounds, we create a new constant called yellowStrayCat and set it equal to yellowCat, since it is still Whiskers. However, we change the name of yellowStrayCat to Smokey. We also create a new constant called yellowStrayDog, setting it equal to yellowDog and naming it Max:

let yellowStrayCat = yellowCat
yellowStrayCat.name = "Smokey"
print(yellowStrayCat.name)

var yellowStrayDog = yellowDog
yellowStrayDog.name = "Max"
print(yellowStrayDog.name)

Our Results Panel shows that the names of yellowStrayCat and yellowStrayDog, respectively, are now Smokey and Max. So, everything seems to be the same between our class and our struct, right? No, they are not the same. Let's print the name of yellowCat underneath the line where we have print (yellowStrayCat.name). In addition, let's do the same for the name of yellowDog underneath where we have print (yellowStrayDog.name). Your code should now look as follows:

let yellowStrayCat = yellowCat
yellowStrayCat.name = "Smokey"
print(yellowStrayCat.name)
print(yellowCat.name)

var yellowStrayDog = yellowDog
yellowStrayDog.name = "Max"
print(yellowStrayDog.name)
print(yellowDog.name)

In our Results Panel, you should notice an unexpected result. The yellowCat, Whiskers, now has the name Smokey, but the yellowDog is still Bruno. Without getting too technical, when you use a class and copy it as we did, it refers back to the original instance created. This is known as a reference type. However, when structs get copied, they create a new instance and the original is not affected. This is known as a value type.

Before we move on, let's look at one more difference between the two. In programming, we have what is called inheritance, which means that we can create another object with default values and other objects can inherit from those default values. Let's create an Animal class that is the base class immediately below our Cat class:

class Animal {
var age:Int?
}

Now, let's update our Cat class to inherit from it, as shown in the following code:

class Cat:Animal {
...
}

Note that we are only updating what goes directly after Cat. The rest of the class in the curly brackets stays the same.

Since our class now inherits from Animal, we should have a new property called age. Underneath where we name yellowCat as Whiskers and above our print statement, enter the following after we set Whiskers' name:

yellowCat.age = 3

So, as expected, we were able to give Whiskers an age. Let's do the same for our Dog struct by adding Animal directly after Dog

struct Dog:Animal {
var name:String?
}

Once you have entered the preceding code snippet, you will see the following:

A red error displays and informs you that Non-class type 'Dog' cannot inherit from class 'Animal'. Therefore, we need to create a struct called AnimalB, since structs cannot have the same name:

struct AnimalB {
var age:Int?
}

Update your Dog struct from Animal to AnimalB:

struct Dog:AnimalB {
var name:String?
}

Now, you should see an error, Inheritance from non-protocol type 'AnimalB', which means that our struct cannot inherit from another struct:

Inheritance is something that you can do with classes, but not with structs; this is another difference between classes and structs. There are a couple of other advanced technical differences but, for our purposes, the two described here are sufficient.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.200.226