3 - Introduction to Swift: Part 3

Welcome to part 3. If you have not seen part 2 or part 1 then check them out as they will ease you in. This lesson is for three very important concepts that will definitely be used consistently throughout iOS programming: Arrays, Functions, and Classes.

Arrays

An array is pretty much just like a list. Simple as that. A list is very useful in programming as it can store a bunch of relevant values in memory to be accessed later on. Let’s start with a list of my friends:

// The way to explicitly create a list of friends (strings)
var array:[String] = ["Collin", "Pat", "Harry"]

// an example of a list of numbers:
var arrayOfNumbers:[Int] = [8, 10, 28, 3, 4]

Similar to declaring a single variable, the way to declare an array is to surround the datatype with brackets and to list the items in the array one after another in brackets seperated by commas.

The cool thing about arrays is that we can actually add, remove, update, and use many different built-in functions with our array:

// Let's create an empty array
var stringArray:[String] = []

// Let's add my name to the array
stringArray.append("Joshua")

// Let's access my name in the array, the first item is always at index 0
stringArray[0]

// Let's add a few more names
stringArray.append("Collin")
stringArray.append("Patrick")
stringArray.append("David")
stringArray.append("Harry")

// Here's how I would access each one of the names individually:
stringArray[0] // Joshua
stringArray[1] // Collin
stringArray[2] // Patrick
stringArray[3] // Starting to get the picture? This one is David
stringArray[4] // Harry

// what if we want to see how many items are in an array?
stringArray.count 

// Let's say we wanted to print everything in the list without individually calling each one, which is repetitive and annoying
for i in 0..<stringArray.count {
    print(stringArray[i])
}

Pretty neat huh? In this last piece with the for loop, we are looping while incrementing the variable i from 0 until the count of the elements in stringArray. We can use the value i to access the different indices of the array so it will loop through the whole array!

There’s a slightly cooler way to do this if it applies to your particular situation:

for i in stringArray {
    print(i)
}

Now in this case, instead of incrementing i, we are actually setting i equal to the first value in stringArray (which is “Joshua”). After the loop executes once, i is then set to the next value in stringArray.

Let’s look into removing elements from the array:

stringArray.remove(at: 3)
stringArray[3]

In our array, the 4th element was the name “David” (which was stored at index 3 [remember that indices start at 0]). Now the element at index 3 is actually “Harry” which was dynamically shifted over to make the array the shortest it could be.

Lastly, updating. Let’s say we wanted to change “Patrick” to “Pat” because he prefers the latter:

stringArray[2] = "Pat"

Simple as that.

Functions

One of the biggest no-no’s in programming is to repeat yourself, meaning writing the same piece of code in many places of a program. This is why we have constants and variables to store data that we will use over and over, so that we don’t have to keep writing explicitly what the data is, so that if the values change we don’t have to go through and fix every spot, we just have to change one part of the code.

Functions are similar in that if we want to perform the same operation multiple times, we don’t have to continuously repeat ourselves. Here’s an example of bad programming:

// What if I want to print the entire contents of our previous array after I add and remove things?
for i in stringArray {
    print(i)
}
stringArray.append("Hello")
// ok now I wanna check to see what the array looks like... guess I have to print everythign again
for i in stringArray {
    print(i)
}
stringArray.remove(at: 0)
// I want to print again to check what I removed... do I really have to write that for loop again?
for i in stringArray {
    print(i)
}

See what I’m getting at? It’s incredibly annoying to rewrite the same for loop in any spot that I want to print the contents of the array. How can I make it simpler? With functions… but before we get to fixing this issue, let’s go over some basic functions:

func printHello() {
    print("Hello!")
}

So what is going on here?

  1. We declare that we are making a function with the func keyword.
  2. We set the name of our function to printHello followed by (). The () indicates that printHello is a function that does not take in any parameters… we will explain a bit more about parameters in a moment.
  3. We designate braces with code inside which will execute everytime the function is called

So after we write our function, we can call it at any time in our code to execute it:

// this will print("Hello!")
printHello()

Let’s do something a bit more complicated. What if we wanted to add two numbers together:

func addition(x:Int, y:Int) -> Int {
    return x + y
}

A little more complicated:

  1. Like printHello, we make the function called addition by using the func keyword.
  2. Now instead of (), we actually have stuff inside of the parenthesis. We have the first parameter called x, which is of type Int, and we have a second parameter called y, also of type Int.
  3. Next we have an arrow pointing to Int. This means that our function will actually output a value of type Int
  4. We then have the curly braces with code inside, and this time we are using the parameters that we created in order to add them together. We use the return keyword to say that we are outputting (or ending our function by returning) the value of x + y.

So we have created a function that takes in a value x and a value y (both of type Int), and returns the addition of the two… How can we use this function now:

// 2 + 2 = 4
addition(x: 2, y: 2)

// 8 + 8 = 16
addition(x: 8, y: 8)

// this will throw an error because you are passing in Doubles instead of Ints
addition(x: 8.0034, y: 12345.929)

We can have a ton of variety when it comes to making our own functions, we can take in multiple datatypes and output any datatype we would like. It all depends on what problem we are trying to solve. The original problem we are trying to solve was that we kept having to rewrite a for loop to print out all of the elements in an array. Here’s the function to fix that:

func printArray(array:[String]) {
    for i in array {
        print(i)
    }
}

We have declared we are making a function with func. We called our function printArray. We named our first parameter array which is of type [String] (remember that arrays of a datatype have brackets around them). And then we write our code within the braces, which is a for loop that goes through the given array and prints every element. So now instead of the repetitive code we had originally, it now looks more like this:

func printArray(array: [String]) {
    for i in array {
        print(i)
    }
}
printArray(stringArray)

stringArray.append("Hello")

printArray(stringArray)

stringArray.remove(at: 0)

printArray(stringArray)

Classes

Let’s take a stab at Object Oriented Programming in Swift. OOP is a method of programming in which we define objects that we want to deal with in containers that we create via code, called Classes. Classes then interact with eachother, can have several variations, etc, etc. In my opinion it is the best way to have organized code if we are going after a large project.

The best way to explain this concept is just to come up with an object we want to define. Let’s pick a person. What are the different things that make up a person?

  1. Name
  2. Birthday
  3. Physical Qualities?
  4. Some other junk?

For the sake of simplicity, let’s assume a person just consists of a name, a birthday, and an IQ!

Here’s how we make a class for a Person. First we define the class:

class Person {

}

Then we need to write the different properties that the class has:

class Person {

    // properties
    var name: String = ""
    var birthday: String = ""
    var IQ: Int = 0

}

Ok we are almost there. So pretty much with this starter code, we have a class called Person with three variables in the class: name, birthday, and IQ. They all start with initial values of either empty string or 0. So in order to create a person, we can do the following.

// Creating a person
let personExample: Person = Person()

// How do we access the different properties?
personExample.birthday
personExample.name
personExample.IQ

Coolio. As you can see, once we created the class Person, we can use the keywork Person to declare constants and variables (similar to setting them to Int or Double or String or whatever). The way we initialize a person is through Person().

But there’s a problem, we don’t want our people to have no name, no birthday, and an IQ of 0. We can do the following to set each of the values of our person… but keep in mind this is not the best practice:

personExample.birthday = "08/08/2008"
personExample.name = "Joe Swift"
personExample.IQ = "888"

// Now when you access their properties, it will have the values you set them to:
personExample.birthday
personExample.name
personExample.IQ

Why is this bad practice? Because that means every time we create a person we have to write an additional 3 lines of code in order to set each of the property values. That is work we don’t need to waste time doing. The way we avoid that is through a special function we can put in our class called init. The following occurs within the already defined Person class:

class Person {
    var name: String = ""
    var birthday: String = ""
    var IQ: Int = 0

    init(nameInput: String, birthdayInput: String, iqInput: Int) {
        self.name = nameInput
        self.birthday = birthdayInput
        self.IQ = iqInput
    }
}

Here’s what just happened:

  1. We created the initialization function called init. This function takes in three different parameters, one each for the person’s name, birthday, and IQ
  2. We list our parameters in the parenthesis after init in the same way as we would for making a function.
  3. In the braces, we are using the keywork self with each of our classes original three variables. We are setting them to be the values that are passed into the init function.

By doing this, when we initialize our Person we have to also pass in the values that we want our person’s name, birthday, and IQ to be. In fact, the line of code that we wrote before should now have an error. This will now be the correct code:

// Instead of this that we had before
let personExample: Person = Person() // Throws an error

// And instead of having to do this junk:
personExample.birthday = "08/08/2008" // ew
personExample.name = "Joe Swift" // yuck
personExample.IQ = "888" // I think I'm gunna be sick

// we now have this:
let personExample: Person = Person(nameInput: "Joe Swift", birthdayInput: "08/08/2008", iqInput: 888)

Ah pretty. This is the basic essense of initializing a class. There are of ton of more things we can do with classes. We can nest functions within our class that do things! Let’s give our Person class a function that let’s it speak:

class Person {
    var name: String = ""
    var birthday: String = ""
    var IQ: Int = 0

    init(nameInput: String, birthdayInput: String, iqInput: Int) {
        self.name = nameInput
        self.birthday = birthdayInput
        self.IQ = iqInput
    }

    func saySomething(){
        print("I am a human!")
    }

}

Now we have a function called saySomething that prints out “I am a human!” This function exists inside of the object, and thus is called through our created person:

personExample.saySomething()
// this should output "I am a human!"

We can write functions that use the properties declared inside of the class for computation. Such as making functions that print out their name or date or how old they are based on the current time. I won’t get into how to do those, but try to use the different methods of interpolation and other programming skills to create those functions.

I will talk about one more thing: Inheritance. Inheritance is when we create a class that extends or inherits the properties and functions from a “parent” class. Say we created a class for Fruit. An example of a another class that would extend class Fruit would be a class of an Orange.

To show you what I mean, here is how we create a class for myself: Josh. The class of myself will extend Person:

class Josh: Person {
    
}

All it takes is the specification that class Josh is extending a person and we can actually use the same initializer and saySomething function without rewriting:

var joshua:Josh = Josh(nameInput: "Joshua", birthdayInput: "11/30/1994", iqInput: 140)

joshua.saySomething()

What if I wanted the Josh class to have the same properties as the Person class, but the saySomething function would print out something different? We can override the function:

class Josh: Person {

    override func saySomething() {
        print("I want to code some swift!")
    }
    
}

Now when we do the following, it will print out “I want to code some swift!”:

joshua.saySomething()

We will get more into the complexities of inheritance as well as the use of optionals in future lessons. Be on the look out for the first actual iOS programming tutorial later this week!

Tags:

Updated: