Explore the intricacies of iOS Development with this in-depth tutorial. Learn about the application of enumerations within a class, instance methods, the difference between class and instance properties, and class methods.
Key Insights
- The tutorial delves into the use of enumerations with classes and explores the properties and methods associated with a class, rather than an instance of the class.
- The tutorial lays out step-by-step instructions on how to effectively use Xcode for iOS development.
- It offers a comprehensive explanation of how to use enumerated types with classes in iOS development.
- A significant portion of the tutorial focuses on using instance methods in a class, explaining how these methods perform actions on an instance of a type, such as a class.
- The tutorial differentiates between class and instance properties, explaining how instance properties can vary between instances, while class properties apply to the entire class.
- Lastly, it touches on class methods and how they can be used to generate or return instances of a class.
Master the use of enumerations, instance methods, class and instance properties, and classes in iOS development with this comprehensive tutorial.
This exercise is excerpted from Noble Desktop’s past app development training materials and is compatible with iOS updates through 2021. To learn current skills in web development, check out our coding bootcamps in NYC and live online.
Topics Covered in This IOS Development Tutorial:
Using Enumerations Within a Class, Using Instance Methods in a Class, the Difference Between Class & Instance Properties, Class Methods
Exercise Overview
Now that you’ve seen how enums work, let’s see how we can use enumerated types with classes. After doing so, we’ll get into the meat of this exercise and dive deeper into classes. You’ll learn about class properties and methods that are associated with the class itself, not an instance of the class.
Getting Started
Launch Xcode if it isn’t already open.
Go to File > New > Playground.
Under iOS, double–click on Blank.
Navigate into Desktop > Class Files > yourname-iOS App Dev 1 Class.
Save the file as: Class Properties and Methods.playground
Click Create.
Basic Enumerations Redux
Later on, we will need to use objects from UIKit. So instead of deleting the entire code, delete only the var str line.
-
Remember that an enumeration is a data structure that lists cases. Create a simple Gender enum with two cases as shown below:
import UIKit enum Gender { case male case female }
-
Let’s assign our enum to a new variable, gender. We’ll set it to the value of female from the Gender type using dot notation. Add the following in bold:
case female } var gender: Gender = Gender.female
-
Type gender as shown below:
var gender: Gender = Gender.female gender
You should see female printed in the right sidebar.
-
Remember that if you want to access a different value from the same enum, you can use shorthand, as the type becomes inferred. Add the following in bold:
gender =.male
-
Let’s test this. Type the bold code:
gender =.male gender
In the right sidebar, you should see male print.
Using Enumerations Within a Class
Now that we’ve refreshed ourselves on how a basic enum works, let’s see how we can use our Gender enum with a class.
-
Delete the following code:
var gender: Gender = Gender.female gender =.male gender
-
Later on, we want to print out these cases. Remember that we will need to integrate them into a string because the print function prints out a string of characters. We can incorporate the contents of the enum into a print function, let’s associate a value of type String to each case by adding the bold code shown below:
enum Gender: String { case male = "male" case female = "female" }
Remember that when we associate cases with raw values such as
"
male"
and"
female"
, each case in an enum must be of the same type. This is why we needed to specify that our Gender enum is of type String. -
Let’s create a new class called Puppy below the enum as shown below:
case female = "female" } class Puppy { }
-
Add the following instance properties to the Puppy class:
class Puppy { var name: String var gender: Gender var breed: String }
Notice that we are setting the gender variable inside the class to the enumerated type Gender. This is how you can incorporate an enum into a class.
-
To get rid of the red error, we need an initializer to create an instance of the type Puppy. Add the following to the bottom of the Puppy class:
var breed: String init(name: String, gender: Gender, breed: String) { self.name = name self.gender = gender self.breed = breed }
-
Using the Puppy initializer, at the bottom of your code add the puppy1 variable shown below:
class Puppy {
Code Omitted To Save Space
} var puppy1 = Puppy(name: "Jack Sparrow", gender:.male, breed: "Sparrow Terrier")
Here we’re calling the Puppy initializer and applying attributes.
-
Now we can read or alter any of the puppy attributes. Let’s get puppy1’s name by adding the bold code:
var puppy1 = Puppy(name: "Jack Sparrow", gender:.male, breed: "Sparrow Terrier") puppy1.name
You should see
"
Jack Sparrow"
in the right sidebar. -
Let’s test the other attributes. Add the following bold code:
puppy1.name puppy1.gender puppy1.breed
The values should print in the right sidebar.
-
Let’s create another puppy. Add the following bold line of code:
puppy1.breed var puppy2 = Puppy(name: "Tinkerbell", gender:.female, breed: "New Yorkshire Terrier")
-
Add a third and fourth puppy:
var puppy3 = Puppy(name: "Siddhartha", gender:.male, breed: "Lotus Setter") var puppy4 = Puppy(name: "Spocky", gender:.male, breed: "Vulcan Retriever")
Using Instance Methods in a Class
The methods we’ve been writing so far are called instance methods because they perform an action on an instance of a type (such as a class). Let’s write an instance method that an instance of the Puppy class can access!
-
Let’s add a method (or function) to our Puppy class. Below the initializer block of code, add the following instance function:
init(name: String, gender: Gender, breed: String) {
Code Omitted To Save Space
} func sayHi() { print("Hi there! My name is \(name). I am a \(gender.rawValue) \(breed)\n") }
NOTE: By specifying a string type for our enumeration, we have given the gender cases raw values.
-
We can call the instance function for puppy1 by adding the following in bold:
puppy1.name puppy1.gender puppy1.breed puppy1.sayHi()
If it is not showing already, click the top right middle button
to show the Debug area.
-
In the bottom Debug area, you should see Hi there! My name is Jack Sparrow. I am a male Sparrow Terrier printed.
Notice that in the right sidebar only Puppy is printed. For complex structure types, the sidebar will only show the content of the class, not the print statement.
-
Let’s tell the other puppies to say Hi as well. Add the bold code:
var puppy2 = Puppy(name: "Tinkerbell", gender:.female, breed: "New Yorkshire Terrier") puppy2.sayHi() var puppy3 = Puppy(name: "Siddhartha", gender:.male, breed: "Lotus Setter") puppy3.sayHi() var puppy4 = Puppy(name: "Spocky", gender:.male, breed: "Vulcan Retriever") puppy4.sayHi()
At the bottom of Xcode you should now see 4 print statements.
-
Let’s see how easy it is to modify our variables. Change the following in bold:
var puppy4 = Puppy(name: "Spocky", gender:.female, breed: "Vulcan Retriever") puppy4.sayHi()
Notice that the print statement changes Spocky’s gender to female.
-
Now add the following line in bold:
var puppy4 = Puppy(name: "Spocky", gender:.female, breed: "Vulcan Retriever") puppy4.gender =.male puppy4.sayHi()
Spocky is male again!
The Difference Between Class & Instance Properties
The properties we’ve been declaring are instance properties. As you just saw, the value for this kind of property can differ from instance to instance. Declaring instance properties allowed us to instantiate puppies with different names, genders, and breeds.
In contrast, we’re going to create a class property, also known as a singleton. It’s called a singleton because no matter how many instances your class has, there will only be one copy of a class property. (This is because each class is unique, and a class property applies to the class as a whole.)
-
The syntax for declaring a class property is pretty simple. Before the var (or let) keyword, you add the keyword static. At the top of the Puppy class, add the following bold singleton:
class Puppy { static var puppies = [Puppy]()
This property we’ve named puppies is currently an empty array that belongs to the Puppy class. We’ll use this one property for all the puppies we create.
-
Let’s see how we can access the puppies property. Type the following:
puppy1.sayHi() puppy1.puppies
Not quite! You will get a red error saying: puppies cannot be used on instance of type Puppy. Instead, we need to call the class itself (Puppy) before being able to access the puppies property.
-
Change puppy1 to Puppy as shown below in bold:
Puppy.puppies
-
Notice that the error disappears and in the right sidebar [] appears, indicating the property named puppies is currently an empty array.
Class properties such as our puppies array apply to the class as a whole. Class properties are useful whenever you need to define an attribute that applies to the entire template (and hence to all the instances that follow that template). Whenever you want to define something that can differ between instances (such as their name), declare it as an instance property.
We want all instances of this class to become part of this array, but how?
-
Now we need to populate the puppies array with all the instances of the Puppy class. To wrangle all those instances into the array, we’ll need to target the instances, not the class. Towards the top of the Puppy class and below the class property, add an instance property (which does not contain the static keyword):
static var puppies = [Puppy]() var puppyIndex: Int var name: String
NOTE: Because this is another instance property like the name and gender, we need to initialize it whenever an object of our Puppy class gets created. Because our init method is now out of date, you will see a red error. We’ll make it go away soon.
-
The new puppyIndex variable will be of the Int data type because it represents each individual instance’s position in the array. We’ve just got one problem—our puppies start numbering at 1, but arrays are zero indexed (start with 0)! To solve that issue, add another property that computes its value based on the puppyIndex:
var puppyIndex: Int var number: Int { return puppyIndex + 1 } var name: String
We are defining number as a computed property as we want our puppies to start numbering with 1, not 0 (the first index in an array). A computed property draws its information from another property, in this case puppyIndex. Here, we’re adding 1 to each puppyIndex, so that our puppy number will always begin with 1.
-
To get rid of the red error, we need to initialize the remaining properties and give them default values. Because the number property computes its value in relation to the puppyIndex property, all we need to do is initialize the puppyIndex and the number will come along for the ride. At the bottom of the initializer code block, add the following in bold:
self.breed = breed puppyIndex = Puppy.puppies.count
At the time each instance joins the Puppy array, this line will count the number of puppies in the array (starting with zero). Then the number property increments that number by 1 behind the scene, giving us a more user-friendly numeric value.
NOTE: This line of code does not need self. We only need to specify self when there’s an ambiguity between a local variable and a property of a class.
-
Add the following code to have each puppy append itself into the array of puppies:
puppyIndex = Puppy.puppies.count Puppy.puppies.append(self)
-
To get the name of the first puppy in the array, go to the end of the playground and add the following:
puppy4.sayHi() Puppy.puppies[0].name
Notice that we don’t need to add a print statement to get the puppy value (which will only appear in the sidebar on the right).
-
Copy the last line of code you just added:
Puppy.puppies[0].name
-
Paste three copies below and change the values shown in bold:
Puppy.puppies[0].name Puppy.puppies[1].name Puppy.puppies[2].name Puppy.puppies[3].name
You should see all four puppies listed in the right sidebar.
-
Let’s change our sayHi() function to include the new number property. Around the middle of the file, add the bold code:
func sayHi() { print("Hi there! I'm puppy number \(number), and m y name is \(name). I am a \(gender.rawValue) \(breed)\n") }
The print statements in the Debug area should update to include the puppy numbers 1–4.
Class Methods
We can use class methods to generate, or return instances of a class.
-
Add a class method that will access the whole array of puppies, and tell each and every puppy to say hi. Before the closing curly brace of the Puppy class, add the following bold code:
func sayHi() { print("Hi there! I'm puppy number \(number), and my name is \(name). I am a \(gender.rawValue) \(breed)\n") } class func listPuppies() { }
-
Add the two print statements, and the for loop between them as shown below:
class func listPuppies() { print("Puppies, please say hi, politely in turn\n") for puppy in puppies { puppy.sayHi() } print("Thank you, puppies\n") }
To break this down, for each puppy in the array of puppies, the puppy will say hi, by calling the sayHi() function.
-
Let’s test our listPuppies() function. At the bottom of the code type the following:
Puppy.puppies[3].name puppy4.listPuppies()
You should get a red error, and Xcode will tell you that the static listPuppies cannot be used on instance of type Puppy. Remember that we need to call the Puppy class instead!
-
Change the code to the following:
Puppy.listPuppies()
You should see the listPuppies() function print in the debug area. Each puppy will say Hi in turn!
-
Let’s add another class function to generate a random puppy. Add the following spawnRandomPuppy() function below the listPuppies() function:
print("Thank you, puppies\n") } class func spawnRandomPuppy() -> Puppy { }
This function is returning an item of the type Puppy.
-
Add the variables shown below.
class func spawnRandomPuppy() -> Puppy { var randomName: String var randomGender: Gender var randomBreed: String }
NOTE: You can ignore any errors in the next few steps. We’ll fix them shortly!
-
Each of the puppies are going to have the same randomName. Add the following in bold:
var randomBreed: String randomName = "…I think I'm a clone…"
-
Let’s define the randomGenderSeed constant. We’ll use the predefined arc4random_uniform function to generate a random number.
randomName = "…I think I'm a clone…" let randomGenderSeed = arc4random_uniform(2)
arc4random_uniform returns a random number between 0 and the parameter in parentheses minus 1. We specified that we want 2 possible choices, so it’ll pick either 0 or 1. This matches the number of cases in the Gender enum.
NOTE: Keep in mind that the arc4random_uniform function is from UIKit. Because we planned on using this function, we did not delete the import UIKit statement from the top of our playground. (If we had deleted it, this line would have thrown an error.)
-
Next, we’ll use a ternary conditional operator to ask if randomGenderSeed is equal to 0. If it is, randomGender will get the value .female. If it is 1 (or not 0), randomGender will be assigned a .male value.
let randomGenderSeed = arc4random_uniform(2) randomGender = randomGenderSeed == 0 ?.female :.male
NOTE: The ternary conditional operator is an operator with three parts, which uses the form question ? answer1 : answer2. The colon (:) means else.
-
Assign the string below for randomBreed:
randomGender = randomGenderSeed == 0 ?.female :.male randomBreed = "…Yeah, I'm definitely a clone :'(…"
-
Now to get rid of the red error, we just need to return Puppy using the original class properties we added:
randomBreed = "…Yeah, I'm definitely a clone :'(…" return Puppy(name: randomName, gender: randomGender, breed: randomBreed)
-
Let’s create a random puppy constant to test our spawnRandomPuppy() class function. At the bottom of your code add the following:
Puppy.listPuppies() let randomPuppy1 = Puppy.spawnRandomPuppy()
Notice that again we are calling the Puppy class.
-
We can get randomPuppy1’s number as shown below:
let randomPuppy1 = Puppy.spawnRandomPuppy() randomPuppy1.number
You should see 5 print in the sidebar, as it’s our fifth puppy!
-
Let’s get randomPuppy1 to say Hi:
randomPuppy1.number randomPuppy1.sayHi()
In the bottom debug area, you should see the new random puppy print statement with a random gender.
-
Let’s generate a few more puppies to see how the random function varies the gender. Copy the three lines of code shown below:
let randomPuppy1 = Puppy.spawnRandomPuppy() randomPuppy1.number randomPuppy1.sayHi()
-
Paste the lines directly below and change the code as shown in bold:
let randomPuppy2 = Puppy.spawnRandomPuppy() randomPuppy2.number randomPuppy2.sayHi()
Check to see whether you got a female or male this time.
-
Paste another copy of the code block, this time changing the number to 3.
let randomPuppy3 = Puppy.spawnRandomPuppy() randomPuppy3.number randomPuppy3.sayHi()
Again, take note of the puppy’s gender.
We’ve just created a class function that spawns random puppies by assigning them a name, a gender, and breed. To make a decision about which attribute from our Gender enum (either male or female) to randomly assign, it uses a ternary conditional operator. Pretty cool! Take note that you could create other class functions using the Puppy class such as one that looks in the puppy array to do an operation such as adding or removing puppies.
Save and close the file. Keep Xcode open, as we’ll use it in the next exercise.
Type Properties & Methods
The class properties and methods you learned about in this exercise are a kind of type property that applies to an entire type. Enumerations and structures can also have their own type properties and methods.
To define enum or struct-wide attributes, you can use the exact same syntax you used for a class property: just add the static keyword before the var or let keyword.
In this exercise, we declared a class method using the class keyword. Obviously, that does not work for enums or structs. For those, just add the static keyword before the func keyword.
NOTE: As you saw in the exercise, the class keyword can be used to declare class methods. However, the static keyword can also be used to declare a class method. So what’s the difference? The class keyword allows a subclass (child class) to override a method inherited from its superclass, and the static keyword does not. The class keyword is sure handy!