Explore Free Swift Tutorials – GameDev Academy https://gamedevacademy.org Tutorials on Game Development, Unity, Phaser and HTML5 Tue, 21 Feb 2023 21:14:49 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.1 https://gamedevacademy.org/wp-content/uploads/2015/09/cropped-GDA_logofinal_2015-h70-32x32.png Explore Free Swift Tutorials – GameDev Academy https://gamedevacademy.org 32 32 How to use Arrays in Swift – iOS Mobile Development https://gamedevacademy.org/arrays-tutorial/ Sun, 05 Jun 2022 01:00:30 +0000 https://swiftludus.org/?p=2324 Read more]]>

You can access the full course here: iOS App Development for Beginners

Arrays

So far, all of the variables that we have seen can only hold one (or zero) values. However, we sometimes need to be able to store multiple values so that we can carry them around in a single variable rather than porting multiple variables around. To do this, we can use an array. This is essentially a list of values. Arrays also have a lot of functionality attached to them to help retrieve or modify certain values or attributes. We won’t explore all of the functions, but we can go over some of the more commonly used ones. First, to create an array, we create a variable but store multiple values within []. We can store values all of the same type or of a single type. Here are some examples:

let testAnswers: [Bool] = [true, false, false, false, true]
let languages = ["Swift", "Java", "HTML"]
let random = [1, false, “hello”, 5.5]

If we want to fetch or modify a single value, we can do so by its index. Indexing is 0 based so the first element is at index 0 and the last is at index of (length – 1). To fetch an item, call upon the index inside of [] beside the name of the array. For example:

let testAnswers: [Bool] = [true, false, false, false, true]
let firstAnswer = testAnswers[0]

This stores the very first value (true) in firstAnswer. There is no built in check to make sure the item exists so be sure to not call an item that doesn’t exist like this:

let languages = ["Swift", "Java", "HTML"]
let someLanguage = languages[5]

You can implement some logic to make sure this doesn’t happen such as checking the length of an array. Do so with arr.count like this:

let languages = ["Swift", "Java", "HTML"]
let languagesLength = languages.count

Modify items using the same methodology. For example, if we wanted to change one of the test answers, we could do this:

var testAnswers: [Bool] = [true, false, false, false, true]
testAnswers[3] = true // testAnswers = [true, false, false, true, true]

As there are many functions, we won’t go over all of them but I’ll provide some examples of some common functions below:

var languages = ["Swift", "Java", "HTML"]
languages.append("CSS") // languages = ["Swift", "Java", "HTML", "CSS"]
languages.insert("Javascript", at: 2) // languages = ["Swift", "Java", "Javascript", "HTML", "CSS"]
languages.remove(at: 3) // languages = ["Swift", "Java", "Javascript", "CSS"]
var firstLanguage = languages.first // firstLanguage = "Swift"

For the last one, it is important to note that firstLanguage is of type String? Because the first element will not exist if the array is empty. We will explore more functions as we go but for a list of all functions, simply type the arrayName. And then you will see a list of functions.

As a quick aside, we can also create ranges of integers with the range operator. To create an inclusive range specify startIndex…endIndex and for an exclusive range specify startIndex..<endIndex. Some examples are:

0...5 // 0, 1, 2, 3, 4, 5
0..<5 // 0, 1, 2, 3, 4

Note that these are not arrays; they are ranges that have slightly different properties and functions.

 

Transcript

What’s up everyone, welcome to part seven of our iOS Development Course, this will be all about arrays. We’ll talk about first, what arrays are, and then how we can use arrays. We’ll also explore some extra array functions, as arrays are special and have a lot of extra functionality attached to help modify, or retrieve, properties or values within an array.

So for starters, what are arrays? They’re essentially just lists of values. We treat them like regular variables, except that they hold multiple values in a single location. Each of the items in an array is stored at a specific index or a specific position. Indexing starts at zero, so the very first element is at index zero, and the very last one is at the length minus one. We fetch, or modify, individual items within an array, by their index. So if we want to change just one of the values within an array, we have to find its index, and then we can modify it.

We can also call upon multiple functions to, again, get or change items or properties within an array. Now, there are many, many functions attached to arrays, so we’ll just go over a few of the basic ones and I’ll leave the rest up to you to explore.

So let’s head on over to the code now. As you can see, I’ve got my Playground up and running again. So this is the iOS Development Playground, I have the project just down here. So let’s talk first about general arrays. Now, the way we set them up is actually very similar to variables. We either call upon and constant or a variable name, and then the name of the array, and then we assign the value.

So let’s try to think about some places where we might have lists within our code. So one of the most common examples that gets brought up when talking about arrays, or lists, is a grocery or a shopping list, so it’s just gonna be a bunch of strings. So let’s create that now, let’s set it to be a variable so that we can modify it, and we’ll call this groceryList. It’s type, although, again, this isn’t needed is going to be an array of strings, like so. And then we set it equal to a list.

So all of the items within an array go within these square brackets, and they’re separated by commas. So let’s say the very first item is gonna be apples. The next item might be bread. After this, maybe we want some cheese or something, and let’s just go with this. So I have the three items within our list, it doesn’t matter, by the way, if they’re up or down, or side-by-side, I just find it easier to read this way. Let’s kinda close that up, I’m not sure why that’s going weird.

So we have a list of strings here, we can access and modify the entire list by doing groceryList, and then setting it equal to something else if we really want, but in this case, we are fine with how it is. So that’s how we can get the entire list by calling upon it just like a variable. But if we want just a single item within the list, we have to get its index. Remember, indexing is zero-based, so this is index zero, index one, and index two.

So let’s say we wanna fetch the very first item, we get our groceryList, and we put the square brackets beside it, and then here we put the index of the item we want to retrieve. So this compiler’s impatient, and it’s waiting for us to do that. So if we want the first item, that’s gonna be index zero, like so. So we can retrieve it, we can store it in something, maybe this is going to be firstGrocery is equal to our groceryList of zero. So what do you think the value should be? Well, it should be apples, it’s going to retrieve basically the item, that it finds in that index, and you can see that it is, indeed, apples. Again, we don’t have to assign the type, although we can say it’s specifically a string, if we’d like.

You should take note of the fact that there’s no array bounds checking. So if we tried to do like groceryList, at the index of five or something, this isn’t gonna work. This is actually gonna throw us an error because this is out-of-bounds. The groceryList is only three items long and here we’re calling for the sixth item in this groceryList. So you always want to check your length before you call upon the index. You can do so simply by doing the grocery, actually the groceryList, dot and then count. So count returns a number of items in the array. When you’re fetching items, always make sure that the index you’re retrieving is less than the count, okay, so just a heads up there.

All right, what about setting items? Well, we do the exact same thing, we get the groceryList, or the array name. In the square brackets, we put the index of the item we want to change, maybe we’re gonna change bread to bagels. So we’re gonna set this, and we’re going to say it’s equal to, maybe we want some bagels. So now let’s take a look our groceryList. This should now say apples, bagels and cheese. And indeed it does, apples, bagels and cheese, like so. So that’s how to access or modify individual items.

Now, I did say that arrays come with a suite of other functionality. In fact, you can access the entire list of functions simply by selecting an array names, so in this case, groceryList, doing dot, and then you can see there are a bunch of different functions here. So many of these are properties, they just retrieve information about the array, such as accounts or the very first element. Note that it’s optional, because the first element may or may not exist. If the list is empty, then this will return nil. Or you can get the last index, you can get the min or max, et cetera, or a lot of these functions help to modify the array in some way. So this means adding items to it, removing items from it, inserting items, et cetera.

So let’s say we want to add an item. I’ll just go over the three common operations adding, inserting and removing. So we can append an entire array, or we can just append one element. This basically sticks an item onto the end. So we want to append let’s say we decided we want eggs, as well. Do we, no, no we don’t have that. So if we print out grocery list, we should see that it contains the four items with eggs, as well. Cool stuff.

Let’s say we want to insert something so we can do groceryList. Actually, let’s go up here, groceryList, dot, insert. And now this takes two arguments. It needs a new element, and it needs a specific index. So let’s say we want to place it second we realize there’s apples, then something then bread and cheese, maybe we want I don’t know, some bananas. Bananas, and we want this at index one because we want to insert it right here. So we go zero, and then one, and that’s where we insert it. And we print out our grocery list, we can go ahead. And we can see that this should contain bananas, as well. Cool stuff.

So what about removing items? Well there’s two ways we can do that. Well, there’s actually multiple ways we can do that. We can remove at a specific index, we can remove everything, we can remove the first, we can remove the last, we can also pop the last element. So in groceryList, dot, popLast, that also does basically the same thing, we’ll stick with the remove function.

So let’s say we want to remove at a specific index. Note that it also returns the element that it’s removing. So let’s say we realize that we no longer need cheese, we have a bunch at home already, so let’s figure out what index that is that is gonna be, I believe, index, let’s pull this out. So we got apples, bananas, bagels and cheese, that’s in index three. So we want to remove the item in index three. We can go ahead and run this and this is now going to return our separation, so it’s going to return cheese. And at this point in time, groceryList has only apples, eggs and then bagels. Or, no, maybe it’s the other way around. I think at this point in time, it would be apples, bananas, and then bagels and then eggs.

So that was pretty much all we wanted to go over. We’re within our time limit, so I’m gonna end it here. Just remember, arrays are lists of items, each item is at a specific index, so it’s important for us to keep track of what items are at what index. We access them to either fetch them or to modify them. We just enter the index, which is zero-based. There’s a bunch of other functions that help us to retrieve properties or to manipulate the array in some way. What I recommend you do is actually explore some of those other array functions. I’ll give you a homework assignment at the end of the next section because we’re gonna be covering dictionaries and the two go really hand-in-hand. So we’ll end it here, thanks for watching, I will see you in the next one.

Interested in continuing? Check out the full iOS App Development for Beginners course, which is part of our Mobile App Development Mini-Degree.

]]>
An Introduction to Text for iOS Apps https://gamedevacademy.org/ios-text-tutorial/ Fri, 29 May 2020 15:00:41 +0000 https://swiftludus.org/?p=2322 Read more]]>

You can access the full course here: iOS App Development for Beginners

Displaying Text

Now that we have learned the basics of storing and changing values, let’s turn to the app development side of things and learn how to display some text in an app. In iOS, we do so using the UI element UILabel. This is just a way to display static text and we can change the text as needs be, even while the app is running. First, we need to start up the project that we created earlier or start a new one. Now open ViewController.swift. We need a label so create a variable to hold a label just above viewDidLoad() so it should look like this:

class ViewController: UIViewController {

    var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

You have to add the ! as we will initialize label in viewDidLoad and that acts as a promise to initialize it before we use it. Next initialize label in viewDidLoad with a CGRect(). Feel free to add whatever x and y value you want as well as width and height but don’t make it too big. Something like this is pretty safe:

label = UILabel(frame: CGRect(x: 100, y: 200, width: 220, height: 50))

Next you want to add some text to the label through the text property. You can assign any string to label.text. Finally add it to the main view (every view added to the page such as labels, buttons, text fields, etc. are children of the parent view) with the view.addSubview() function, passing in your label. The final code should look something like this:

label = UILabel(frame: CGRect(x: 100, y: 200, width: 220, height: 50))
label.text = "Welcome to my app!";
view.addSubview(label)

Make sure this code is in viewDidLoad and run the app. You should see a blank screen with some text near the top (whatever String you assigned).

 

Transcript

What is up everyone, and welcome to part six of our iOS development course. Here we’re going to learn how to display text within an app. It’s a very important part of pretty much any app as you’ll likely need to display some sort of label or text throughout the app’s execution. So we’re going to talk about how to display text, we’re going to talk also about how to add UI Elements and use them.

So when we add UI Elements to code, we can get access to their properties and attributes and that’s what we’re going to do. We’re going to interact with the UILabel, we’ll be able to change text attributes, and then this we’ll be able to display the exact text that we want.

So we’re going to start off with the label, we’re going to add it to the page or the screen as a variable. And then we can access and modify the properties. In our case again, we’re just going to be using the text property, although there are many others that we can modify. So we’ll explore those a little bit as well.

So let’s head on over to the code. And as you can see I have this project started up. This is iOS Development. If you remember when we were exploring Xcode, I started a project called iOS Development, that’s exactly what this is starting out with a blank page, you’ll want to get yourself a project started up, I have also my playground here by the way, I just minimized it. And we’re only going to be working ViewController.

So as soon as you open that up, you can actually close that panel up there. Okay. So if we run this app right now, it’s just gonna show a plain white screen, there’s nothing on the storyboard and there’s nothing in the ViewController. What we want to do is simply display a label with some text, that text can say whatever we want on it. So the first step will be to create the label to hold the text then we can change the text, then we can add it to the screen.

So I think probably the simplest way of doing this is creating a variable in here or you can create the label and then work within viewDidLoad. But for now we’re just gonna work with everything in here. Okay. So make sure it’s within this viewDidLoad function. This is essentially the one that is called as soon as this screen comes into play. So there will be a screen associated with this ViewController. As soon as it appears on your device, this function is called so this is used to do all the setup.

So we’ll start off with a constant, this is just going to be our label, okay. And this is going to be an instance of a UILabel. Okay, so we wanna select this guy. And we’ll actually want to pass on a frame right away. Okay, so this frame is going to need an argument. This argument is going to be a CGRect. So this stands for Core Graphics Rect, or Core Graphics Rectangle. So a rectangle is going to have four coordinates, it’s going to have an x and y position. And it’s going to have a width and height, we need to specify all for those in this label.

Now, generally speaking it’s a good idea to take different screen sizes into account. So you probably don’t wanna use absolute numbers like 50, or 100. However, we’re not really building a real app, we’re just using this tutorial, and this project to explore some app concepts. So it’s okay in our case. If you want more tips on app development techniques, then feel free to take some of our other courses. However, for now we’re just going to create a rectangle.

So let’s create something called a labelRect. This is going to be a CGRect like so. If we open up the brackets, you’ll see there’s a few constructors we can use. So doesn’t really matter which one, I would recommend using one of these guys, these last three. Okay, this allows us to enter an x and y position, and a width and a height. For now we’ll just do something like 50 for the x position 100 for the y position, a width of maybe 200 and a height of 100. Doesn’t really matter what figures you enter in here, you’ll probably want at least these numbers, just at least like I don’t know, you could do a hundreds on all of them. That will make sure that’s big enough to hold some text.

Okay so when we create this label, we’re going to pass it in our lableRect. You could alternatively just use this right in here. You don’t have to create the variable but that’s up to you. Okay so we have a label. We have its position and its size. And now we want to assign some text to it. So what we’re gonna do is we’re gonna call upon our label, dot, and now this will give us access to all of the properties. There are lots of properties, attributes, functions that we can call upon this.

Note that we can give it some attributed text. We can change its font. We can change whether its highlighted or not. We can set the number of lines. We can change the text itself, text color, we can change the background color, etc. For now all we’re going to do is we’re going to set some text.

Note that this text is optional. It’s an optional string. The reason it’s an optional string is because this is used to both set the text and retrieve the text. So if I said something like variable someString is equal to my label text. This label might not have text. So that’s why this is optional, okay, because of this label doesn’t have text, then this will take on the value of nil. In our case, we’re not retrieving anything. We’re actually setting something.

So we’re just going to say label.text is equal to, and then we’re just going to set some string. So remember, strings are used to represent text data. So this is the perfect chance for this. So feel free to enter whatever string you like. I’m just gonna say, “Hello, my name is Nimish”, like so. Okay this should fit all on one line. But just in case it doesn’t, I’m going to say label.numberOfLines is equal to two. This will make sure that this fits over multiple lines, if needs be. Okay, cool stuff.

So we have a rectangle with a specific size and position. We have a text assigned to this label. We have a number of line set. So now all that’s needed is to add this to our main screen. So every ViewController controls a specific view. So if we call upon view, you’ll see that this is a view that this ViewController managers. We want to add every UI element to this view or to some child of this view. We’ll talk more about child hierarchies in a few sections from now. For now, what we’re gonna do is we’re gonna say, view.addSubView, Okay?

Note that this takes any UI view. Well a label is actually a subclass of view UIView. So we can actually just pass in our label here. So basically, we’re taking our view our overall screen view and we’re adding this label to it. This label has all of these properties and so we should see this label with “Hello, my name is Nimish” or whatever text you put there displayed when we’re going to run it. So that’s gonna be our next step.

Let’s go ahead and we can run this guy. So build succeeded, it’s looking good so far. Let’s see if there are any errors here. Okay, there we go. So 50 is not very far from the edge and 100 is not very far from the edge there so you can see that we get this nice label with whatever text you assigned. It only spans just a little bit. We didn’t actually need this numberOfLines equal to two but just in case if you have a large phone or a lot of text then it might overflow.

Okay but that is it for this tutorial. You’ve learned how to add or how to create UIviews, in this case a label. You’ve learned how to change some properties of these Uiveiws and you’ve learned how to add them to our screen with this view.addSubview. In the next session, we’ll be actually going back to the language basics. We’ll need to learn a little bit more before covering the next part of our app development tutorial. So that’s it, thanks for watching. See you guys in the next one.

Interested in continuing? Check out the full iOS App Development for Beginners course, which is part of our Mobile App Development Mini-Degree.

]]>
Structs and Enums in Swift https://gamedevacademy.org/structs-and-enums-in-swift/ Wed, 04 Jan 2017 13:00:27 +0000 https://swiftludus.org/?p=1992 Read more]]>  Structures

We’ve discussed classes in Swift and how they are the foundation of object-oriented programming. In addition to classes, we also have structures that provide similar functionality. A structure is similar to a class since it can also have methods, properties, and initializers, but a structure is a value type where classes are reference types.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

Every type in Swift is either a value type or reference type. A value type, such as Int or Bool, is a type whose value is copied when it is assigned to another variable or literal, or passed through a function/method. On the other hand, a reference type is a type whose value is aliased instead of copied. Let’s take a look at the difference visually.

value-reference-type

Since Int is a value type, when we assign b to a, we simply copy the value of a. If we change b, we do not affect a in any way. In the case with the reference type, b is now an alias to a. This means that when we change b, we also change a because they are aliases of each other. They are different names for the same instance!

It is very important to remember that structures are value types! When we set a variable equal to a struct, we’re actually making a copy of that structure! This behavior also exists for function parameters that are value types.

If we have value type parameters, we are passing by value; if we have reference type parameters, we are passing by reference. It is important to note this distinction because it can have drastic effects on the behavior of our code! Consider a method to swap two Ints.

func swapInts(a: Int, b: Int) {
    let temp = b
    b = a
    a = temp
}

We get errors! Swift knows that an Int is a value type and tells us that we cannot assign to a method parameter! To make Swift treat a value type as a reference type, we use the inout modifier on the parameters.

func swapInts(a: inout Int, b: inout Int) {
    let temp = b
    b = a
    a = temp
}

Now this function will do exactly what we expect it to do! Swift doesn’t provide us a way to treat a reference type as a value type; instead, we usually create a new instance and copy over property values.

If we were to implement the same swapping function with a reference type, we wouldn’t need the inout modifier since the parameters become aliases to the instance we pass in! This means that parameters of a reference type can affect the instance itself, not a copy!

One small difference between structs and classes is that we cannot implicitly change the properties of a struct within an instance method because structs are value types. We need to explicitly state that an instance method alters one our struct’s properties using the mutating keyword. Consider a struct that represents a circle. We define a circle by its center and radius.

struct Circle {
    var centerX = 0.0, centerY = 0.0, radius = 1.0
}

Suppose we wanted to add a function to double the radius of the circle. Since structs are value types, we need to add the explicit mutating modifier on our method like this.

struct Circle {
    var centerX = 0.0, centerY = 0.0, radius = 1.0
    mutating func doubleRadius() {
        radius = radius * 2
    }
}

Now we can modify our property! When we use this method, we change the value of the property for that original instance of the structure; we do not have to create a copy!

If we had a constant structure defined using the let keyword, we would not be able to change any of its properties! With classes, constants are different. If we declare a constant to an instance of a class, we are not allowed to reassign the constant to another instance. However, we are permitted to change the properties on that constant! So the properties of the instance of the class are not constant, but the instance it refers to is! In other words, we cannot change which instance the constant points to, but we can change the properties on that instance.

To recap, let’s list the differences between classes and structures.

  • Classes are reference types!
  • Classes can use inheritance
  • Deinitializers are only valid in classes since they are reference types!
  • Classes can change their properties without the mutating modifier
  • Class properties can be modified if it is declared as a constant with the let keyword

In other cases, structures have the same functionality as classes.

Enums

In addition to structs and classes, we also have enumerations! An enum is way we can group related values and use them in a type-safe way. Like struts, enums are also value types! For example, let’s suppose we want to represent the planets of our solar system. We could do this by using a number of constants like this.

let mercury = 1
let venus = 2
let earth = 3
...

But someone could assign an invalid value in our code!

var currentPlanet = -1 // not a valid planet!

We would need to introduce many lines of code for type checking to make sure we’re only assigning valid values! But there is a much easier way using enums!

Let’s declare an enum that represents the planets!

enum Planet {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}

An enum declaration is similar to a class or struct. Inside of the body, we use the case keyword and supply the comma-separated list of values. Now when we use an enum type, we can only select values that are defined in the enum.

var currentPlanet = Planet.mercury
currentPlanet = -1 // error!

A shortcut that we can use when reassigning enums is to omit the enum name entirely. This is because we have already established that the given variable is of an enum type; we can only assign it values within that enum.

var currentPlanet = Planet.mercury
currentPlanet = .earth
currentPlanet = .neptune

Notice that we don’t have to reuse the name of the enum!

This same type-checking safety works with switch statements as well! We can also omit the enum name and use the value since Swift will know that the variable we’re switching on is of an enum type.

switch currentPlanet {
case .earth:
    print("Home Sweet Home!")
default:
    print("Not home!")
}

We can also give each enum value any number of other values as well. These are called associated values. For example, consider colors. We can represent a particular color in many different ways! We can use the usual red, green, and blue (RGB) colorspace. We could add an alpha level: ARGB. We could use the cyan, magenta, yellow, and key (CMYK) colorspace. There are many different options we could use to represent a single color! Each option has a different number of values, and we can use associated values to make this distinction.

Let’s create our color enum and add a few colorspaces.

enum Color {
    case rgb(Int, Int, Int)
    case argb(Int, Int, Int, Int)
    case cmyk(Int, Int, Int, Int)
    case name(String)
}

When we define an enum like this, we’re telling Swift that each case can have its own associated values. We can set these associated when we create an instance of an enum.

var blue = Color.rgb(0, 0, 255)

When we declare this variable, we’re saying that its type is the Color enum type with value rgb and it has an associated tuple value of (0, 0, 255). This adds more power to enums because we can attach extra values that we can use.

We can also re-assign using the same shorthand syntax.

var blue = Color.rgb(0, 0, 255)
blue = .argb(100, 0, 0, 255)
blue = .name("blue")

This associated value becomes very useful when we add switch-case statements. We can decompose the associated tuple value inside of the particular switch case corresponding to the enum value and its associated values.

switch blue {
case .rgb(let red, let green, let blue):
    print("R: \(red) G: \(green) B: \(blue)")
case .argb(let alpha, let red, let green, let blue):
    print("A: \(alpha) R: \(red) G: \(green) B: \(blue)")
default:
    print("Not RGB or ARGB!")
}

Now we have access to each tuple value in the case block of the switch statement! Note that these are constants so we cannot modify them in the switch case. We would have to change the variable blue itself.

Notice that we’re using the let keyword three or four times: one for each value in the tuple. Swift gives us a shortcut that we can use to simply this: just one let at the beginning!

switch blue {
case let .rgb(red, green, blue):
    print("R: \(red) G: \(green) B: \(blue)")
case let .argb(alpha, red, green, blue):
    print("A: \(alpha) R: \(red) G: \(green) B: \(blue)")
default:
    print("Not RGB!")
}

This looks much cleaner!

In addition to associated values, we can also have raw values. We can assign a raw value, each of the same type, to each case in the enum. Let’s revisit our planet example and give raw values to the planets. We can have implicitly assigned raw values when we just assign the first case a value; Swift will imply the rest as a linear sequence.

enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}

print("Mercury's position in the solar system: \(Planet.mercury.rawValue)")

The type of the raw value must be denoted in the enum declaration, in this case Int. Notice that we only have to assign mercury a value of 1, and Swift will imply the rest will be one plus the previous. So venus will have a raw value of 2; earth will have a raw value of 3; and so on.

One good use of this is initializing from a raw value. We can select the enum case depending on the raw value that we pass in like this.

let thirdPlanetFromSun = Planet(rawValue: 3)

Notice that this returns an optional since we could have supplied a bad value! We have to safely unwrap it before we use it!

To recap, enums are a type-safe way we can group related values. Enum cases can store data in the form of associated values or raw values. The types of the associated values can be different for each enum case, but the raw value type has to be the same for all cases in an enum.

]]>
Object-oriented Programming with Swift – Part 2 https://gamedevacademy.org/object-oriented-programming-with-swift-part-2/ Wed, 21 Dec 2016 13:08:46 +0000 https://swiftludus.org/?p=1983 Read more]]> Initialization and Deinitialization

Initialization is when we prepare to create an instance of a class. This process may involve configuring the properties or any other miscellaneous setup required before we can use that instance like opening a database connection, creating a save file, or opening a web socket.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

In Swift, we use initializers to run some code before the instance is created. These initializers look like methods but have a very specific method signature: they must be named init and return nothing. We use them to simply setup the instance, and Swift will handle the act of creating the resources for that instance for us.

Let’s see how we can create an initializer in Swift.

class Game {
    var numberOfPlayers = 2
    init() {
        print("Starting game...")
    }
}

var game1 = Game()

Since our initializer does not take any parameters, we use empty parentheses. Now when we create an instance of game, we should see “Starting game…” appear. It is important to note that an initializer is called each time we create an instance of a class.

Notice that we have a property the defines the number of players our game has. If we wanted our game to have 4 players, we would currently have to do the following in two lines of code.

var game1 = Game()
game1.numberOfPlayers = 4

However, remember that initializers can be used to configure properties! We can create another initializer that overloads this one and takes a parameter. Method overloading is when we have two methods with the same name, but different parameters or return types. Let’s create another initializer to configure the number of players.

class Game {
    var numberOfPlayers = 2
    init() {
        print("Starting game...")
    }
    
    init(numberOfPlayers: Int) {
        self.numberOfPlayers = numberOfPlayers
    }
}

We have a second initializer with the same name, but different parameters. This is ok because Swift can use the parameters and return type to differentiate which method we’re referring to. Now instead of two lines of code, we can use a single line of code to create an instance of game with 4 players.

var multiplayer = Game(numberOfPlayers: 4)

Notice that the parameter-less initializer is not executed when we overload this initializer. We can categorize initializers into designated and convenience initializers. The two initializers that we declared are designated initializersConvenience initializers are required to call a designated initializer. If we wanted to make the parameter initializer call the parameter-less initializer, we can convert it into a convenience initializer by adding the convenience modifier.

class Game {
    var numberOfPlayers = 2
    init() {
        print("Starting game...")
    }
    
    convenience init(numberOfPlayers: Int) {
        self.init()
        self.numberOfPlayers = numberOfPlayers
    }
}

Now when we create a new instance of Game with the convenience initializer, we call the designated initializer.

We can also have failable initializers that use optionals. Instead of returning a definite instance, we can have the initializer fail and return nil. We can make the convenience initializer into a failable initializer and have it return nil if the number of players provided is less than zero.

class Game {
    var numberOfPlayers = 2
    init() {
        print("Starting game...")
    }
    
    convenience init?(numberOfPlayers: Int) {
        if numberOfPlayers < 0 {
            return nil
        }
        self.init()
        self.numberOfPlayers = numberOfPlayers
    }
}

We can convert a regular initializer into a convenience initializer by changing the name to be init?. Now when we create an instance, we get an optional!

The complimentary process to initialization is deinitialization. This happens when Swift re-collects the memory and resources of an instance. This process usually cleans up the instance like closing any connections and writing to files.

We can create a deinitializer by using the deinit keyword. They’re similar to initializers because they require a specific name, parameters, and return type. Let’s create a deinitializer for our game class.

class Game {
    ...
    deinit {
        print("Quitting game...")
    }
}

To see the deinitializer in action, we have to create an optional instance of Game. We can use the failable initializer to do that!

var multiplayer = Game(numberOfPlayers: 4)
multiplayer = nil

When we set an optional to nil, we invoke the deinitializer! In most cases, we won’t need an explicit deinitializer, but it is ideal for closing connections, saving, or undoing code in the initializer!

Inheritance

One of the fundamental object-oriented principles is inheritance. Inheritance is a concept we use for creating hierarchies of classes. Consider a real-world example. All dogs are mammals and inherit traits of mammals. Similarly, all humans are also mammals and inherit traits of mammals as well. However, dogs and humans have their own traits that make them unique. We can model this same hierarchy in software using inheritance.

We can have a base class or superclass called Mammal and create a subclass Dog that inherits all of mammal’s methods and properties.

class Mammal {
    ...
}

class Dog: Mammal {
    ...
}

Dog is a subclass of Mammal and Mammal is the superclass of Dog. The properties and methods of Mammal are accessible from the Dog subclass. For example, let’s add some methods and properties.

class Mammal {
    var numberOfLegs = 4
    var hasTail = true
    
    func speak() {
        print("Speaking!")
    }
}

class Dog: Mammal {
}

let fido = Dog()
fido.speak()
fido.numberOfLegs
fido.hasTail

Notice that Dog is just an empty class, but we can access and use the properties and methods of Mammal since Dog inherits from Mammal.

Something isn’t quite right though: the speak method. We want each subclass to define its own behavior for speaking. We can have our Dog subclass provide its own behavior for the speak method by overriding it. When we override a method, Swift will use the code in our overridden method instead of the superclass’s code. We can override a method in Swift using the override modifier.

class Dog: Mammal {
    override func speak() {
        print("Woof!")
    }
}

Now if we ran the speak method on an instance of Dog, we would see “Woof!” printed! In addition to overriding methods, we can also override property getters and setters to provide our own implementation.

If we wanted to run code in the superclass, we have access to the super keyword, which refers to the superclass. We could execute the superclass’s speak method by typing super.speak(). If our superclass did some extra initialization for us that we wanted to take advantage of, we could use the super keyword and execute that code.

We can prevent subclasses from overriding our methods or properties by using the final modifier.

class Mammal {
    var numberOfLegs = 4
    var hasTail = true
    
    final func speak() {
        print("Speaking!")
    }
}

The Dog class should throw an error because we cannot override properties or methods that are declared with the final modifier.

Access Modifiers

Access modifiers are modifiers we put on classes, methods, and properties to limit their visibility. This allows us to hide one part of code from other parts of our code. Swift code can be split across multiple files and can have multiple classes in the same file. This gives us, the programmer, flexibility in how we write our code. We’ll talk about a few modifiers like public, internal, fileprivate, and private.

The public modifier simply means that anyone can access the property, class, or variable or call the method or function. This is the most open of all of the access modifiers.

The internal modifier restricts access to within our module. (A module is a group of Swift files containing related classes.) This is the default access modifier! Unless we have a specific reason to use this modifier, we should stick with the others described in this section.

The fileprivate modifier restricts access to within the file that the thing is defined in. We have this access modifier so that we can declare different classes that can share a variable using the fileprivate modifier.

Finally, the most restrictive modifier is the private modifier which restricts access to within the class only. Any property or method declared with the private modifier is inaccessible, either for reading or writing, outside of the class. For example, let’s make the numberOfLegs property private.

class Mammal {
    private var numberOfLegs = 4
    var hasTail = true
    
    func speak() {
        print("Speaking!")
    }
}

let fido = Dog()
fido.speak()
fido.numberOfLegs // error!
fido.hasTail

Even though Dog is a subclass, since numberOfLegs was defined in the Mammal class, we can’t access it outside of that class!

This discussion on access modifiers leads us to our second object-oriented programming principle: encapsulation or data hiding. Encapsulation is the practice of keeping the internal state of an object private while providing methods to all the outside world to access that internal state in a safe way. Take a look at the following diagram.

3-5-encapsulationHere we’re modeling a car. We have the internal state of the car kept inside of the inner circle. The outer shell is that of the different methods that we have, called getters and setters. In our case, we use Swift’s built-in property getters and setters for this. Using encapsulation, we only allow access to the internal state of our car in a safe way through methods or getters and setters. This helps maintain constraints on our state and prevents someone from changing our state to an invalid state.

For example, if we exposed the state to the world, we might accidentally change the gear to a negative value! Instead, we use a setter and only change the internal state if the input is valid. This concept also works with getters. For example, suppose it is more efficient internally to keep color stored as a low-level representation using raw bytes. That’s not human-readable at all! However, in the getter, we could do the conversion to make the color human-readable and useable!

As a general rule, we should always follow encapsulation and keep the internal state of our class internal using the private access modifier, and use methods, or getters and setters, to allow accessing and mutating that state.

Fundamental object-oriented programming principles

We’ve already seen two principles of object-oriented programming: inheritance and encapsulation. We’re going to discuss abstraction and polymorphism. Let’s go back to our mammal class and create several different subclasses with their own speak method.

class Mammal {
    func speak() {
        print("Speaking!")
    }
}

class Dog: Mammal {
    override func speak() {
        print("Woof!")
    }
}

class Cat: Mammal {
    override func speak() {
        print("Meow!")
    }
}

class Human: Mammal {
    override func speak() {
        print("Hello!")
    }
}

We know, since Mammal is a superclass, we can declare a variable of type Mammal and assign it to an instance of any of its subclasses.

let fido: Mammal = Dog()
let mittens: Mammal = Cat()
let bob: Mammal = Human()

All of the above variables are of type Mammal. Let’s see what happens when we execute the speak method.

fido.speak()
mittens.speak()
bob.speak()

We might expect to just see “Speaking” printed, but we get the correct string printed to the screen! This is because of polymorphism! It allows us to abstract the implementation details of the speak method! Even though our variables are of type Mammal, Swift knows that the type of the instance has its own speak method and will use that in place of Mammal’s implementation. This allows us to abstract the implementation details of each individual subclass’s speak method into the superclass’s method. We can use the speak method and know that Swift will call the right one!

In this section, we discussed initialization, access modifiers, and core object-oriented programming principles. We use initializers to set up an instance by configuring properties or other setup. Access modifiers are used to restrict access to properties and methods in our Swift code and led to our discussion about encapsulation, or data hiding. Encapsulation is an OOP principle that allows safe access to our internal state. Inheritance is another principle that allows us to create hierarchies of classes through a super/subclass relationship. Finally, we discussed polymorphism, which allows us to use abstractions so we don’t necessarily know or care about the underlying details of an implementation.

]]>
Object-oriented Programming with Swift https://gamedevacademy.org/object-oriented-programming-with-swift-2/ Wed, 14 Dec 2016 13:09:48 +0000 https://swiftludus.org/?p=1979 Read more]]> Basic Object-oriented Principles

Before delving into Swift code, let’s first understand what it means to be object-oriented (OO) and the need for OO. We begin our discussion by talking about classes and objects.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

In software, sometimes it is not sufficient to have loose methods and data structures floating around in our source code. We need some structure to group similar attributes and actions. Let’s look at an example.

Imagine we’re working in a factory that makes cars. We have several different models of cars that our assembly line produces from a blueprint. The machines along the assembly line are already programmed with the blueprint and perform the necessary actions to construct a functioning car at the end of the assembly line. When we’re making a multiple cars of the same model, the assembly line guarantees that the resulting cars are identical.

Suppose we wanted to model this assembly line in our Swift code. We might have something like the following.

var color = "Red"
var numberOfDoors = 2
...

But this code is ambiguous! Which car is red? Which car has 2 doors? If we wanted to make different cars, we would have to prefix each attribute a car has with the name of the different cars we wanted to create. This leads to a variable-naming and code quality nightmare!

Instead, we can bundle a car’s states and behaviors into a class. A state is just some attribute about the car, like color or number of doors. A behavior is an action that the car can perform, like drive forward or turn left. A class is just a blueprint for a software object or instance that bundles the states and behaviors. It allows us to represent a real-world thing, like a car, in our source code. We create an instance or object of a class when realize that blueprint. Think of it like constructing a new car after it has gone down the assembly line.

Let’s see some Swift code and create a class to represent a car.

class Car {
    var color = "Red"
    var numDoors = 4
    var speed = 0
    var gear = 1
    var hasSunroof = false
    var sunroofOpen = false
    
    func stop() {
        speed = 0
    }
    
    func increaseSpeed(_ speedToAdd: Int) {
        speed = speed + speedToAdd
    }
    
    func decreaseSpeed(_ speedToSub: Int) {
        speed = speed - speedToSub
    }
    
    func openSunroof() {
        if hasSunroof {
            sunroofOpen = true
        }
    }
    
    func closeSunroof() {
        if hasSunroof {
            sunroofOpen = false
        }
    }
}

This class has states and behaviors that we used to represent a car. The states are called properties in Swift. They look like variable declarations except inside of a class. Behaviors are called methods in Swift and look like functions inside of the class declaration. We’ll be discussing them in more detail later.

Now that we’ve defined a blueprint for a car, we can create an instance, or instantiate, a new car similar to any variable  in Swift.

var newCar = Car()

This new car will start with all of the default values of the properties, i.e. Red, 4 doors, etc. We can access and modify different properties on this instance by using the dot operator (.) after the variable name. For example, let’s make our car blue instead of red.

newCar.color = "Blue"

We used the variable name, dot operator, and property name to change the value of the property. We can do the same to access the property:

let newCarColor = newCar.color

We can call methods using the same dot operator and syntax, except we use the method name and type it like we’re calling a function.

newCar.increaseSpeed(25)

Now that we’ve seen how to use classes and instances, we’re going to delve more into properties and methods so we can build better object-oriented Swift code.

Properties

As we’ve seen before, properties represent the state of an object, and we can access the properties of an instance using the dot operator. Properties can be of any data type, even other classes! Consider a class representing a stick of RAM.

class RamStick {
    var totalRam = 2
}

Computers have slots that RAM sticks can fit into to give our computer more RAM! Let’s make a computer class with 4 slots for RAM.

class Computer {
    var ramSlot1 = RamStick()
    var ramSlot2 = RamStick()
    var ramSlot3 = RamStick()
    var ramSlot4 = RamStick()
}

var myComputer = Computer()

The properties in this class are actually instances of other classes! We have 4 RAM slots here, but it might be the case that we don’t use all of them all of the time! But what we’re doing here is wasting resources by forcing Swift to create 4 instances of RamStick for each instance of Computer that we create.

Instead, we can use lazy properties to tell Swift that we want to create the instance only if it’s being used. To declare a property to be lazy, we simply add the lazy modifier.

class Computer {
    var ramSlot1 = RamStick()
    lazy var ramSlot2 = RamStick()
    lazy var ramSlot3 = RamStick()
    lazy var ramSlot4 = RamStick()
}

var myComputer = Computer()
myComputer.ramSlot1.totalRam = 4
myComputer.ramSlot2.totalRam = 4

Now when we create an instance, the only instance of RamStick created is ramSlot1. However, if we were to access a property on a lazy property, Swift will create the instance. In the above case, ramSlot3 and ramSlot4 are not created yet and may not ever be. This saves us some resources! Imagine making hundreds of computer instances in an array! All of those savings add up!

In addition to lazy properties, we can also have computed properties. These are properties whose values are computed from the values of other properties. For example, consider the total RAM of a computer: it is the sum of the all of the RAM in the RAM slots.

class Computer {
    var ramSlot1 = RamStick()
    lazy var ramSlot2 = RamStick()
    lazy var ramSlot3 = RamStick()
    lazy var ramSlot4 = RamStick()
    var totalRam: Int {
        get {
            return ramSlot1.totalRam + ramSlot2.totalRam + ramSlot3.totalRam + ramSlot4.totalRam
        }
        set {
            ramSlot1.totalRam = newValue
        }
    }
}

We can write code that happens when we access or modify this property. When we access this property, we compute the total RAM from the RAM slots in the get block. When we set this property, we assign all of the RAM to the first RAM slot in the set block. The variable newValue is a context-specific variable that represents the new value we’re setting to, or the right-hand side of the assignment operator in other words. If we omit the set block, we can have a readonly computed property that we can access but not modify.

So far, we’ve only discussed instance properties, meaning that the values are tied to an instance, and each instance has its own values for each property. We can also have type properties whose values are bound to the type, not any particular instance. For example, suppose we wanted to keep track of all of the computers that were manufactured. We don’t want each instance to keep track of that because the numbers will all be different! Instead, the Computer type should keep track of this.

class Computer {
    static var numberOfComputers = 0
    ...
    func manufacture() {
        ...
        Computer.numberOfComputers += 1
    }
    ...
}

var computer1 = Computer()
comptuer1.manufacture()
Computer.numberOfComputers
var computer2 = Computer()
comptuer2.manufacture()
Computer.numberOfComputers

We have a type property numberOfComputers declared with the static modifier. We don’t access it through a particular instance, but through the type name. The first time we print its value, we get 1b and the second time will be 2. This is because we can update it in the instance methods, but the value is tied to the type, not a particular instance. Whenever we manufacture a computer, we increment the total number of computers created. Always remember that type methods are bound to the type!

Methods

As we’ve seen before, methods represent the behavior of an object, and we can call methods on an instance using the dot operator. By behavior, we’re really asking the question “what can this object do?” Syntax and functionality-wise, methods operate very similarly to functions except they’re bundled into a class now.

Similar to properties, we can have instance methods and type methods. Instance methods are called on the instance, and type methods are called on the type. The rule with type methods is that we cannot access instance properties in a type method since we’re not calling it on an instance! Hence we can’t access any instance data, because there is no instance!

class Computer {
    static var numberOfComputers = 0
   
    static func printTotalManufactured() {
        print(numberOfComputers) // OK to access since it is a type property!
        //print(totalRam) // NOT OK! totalRam is an instance property and relies on having an instance!
    }
    ...
}

Computer.printTotalManufactured()

Declaring a method to be a type method is similar to declaring property to be a type properties: add the static modifier! We call the type method on the type, similar to how we access type properties.

Methods without that static modifier are instance methods and require an instance. Instance methods also have access to a special, implicit variable called self. self refers to the current instance that we’re executing the method on. Usually, we use it to disambiguate between method parameters and instance properties. Consider this example.

class Computer {
    ...
    
    var isOn = false
    func changeStatus(_ isOn: Bool) {
       isOn = isOn
    }
}

When we perform the assignment, are we assigning the property to the parameter or the parameter to the property? We use the self keyword to refer to the current instance so we can disambiguate.

class Computer {
    ...
    
    var isOn = false
    func changeStatus(_ isOn: Bool) {
       self.isOn = isOn
    }
}

This code is unambiguous since self.isOn refers to the property on the current instance, which is the instance property isOn and not the parameter.

Since we use it to refer to the current instance, we cannot use the self property in a type method because we have no instance!

In this section, we discussed some basic object-oriented concepts like classes, properties, and methods. We discussed the difference between classes and instances. We learned about states and behaviors in the form of Swift properties and methods, respectively. We also took an in-depth approach to learning about properties and methods.

]]>
Swift 3 – Learn to Code with Apple’s New Language https://gamedevacademy.org/swift-3-learn-to-code-with-apples-new-language/ Wed, 09 Nov 2016 01:56:55 +0000 https://swiftludus.org/?p=1845 Read more]]> Be part of the evolution of Swift 3! There is no better time to learn this powerful , yet easy to learn programming language developed by Apple for macOS, IOS, watchOS and tvOS. This course is designed to provide a comprehensive introduction to Swift, so that you can begin experimenting right away.

Mobile devices are everywhere. They have changed the way we communicate, do business,  access news, and entertainment.   Mobile app development is the fastest growing area in software development and it shows no signs of slowing down. Don’t get left behind.

Access this course on Zenva Academy

]]>
Intermediate iOS – Get Job Ready with Swift 2 https://gamedevacademy.org/intermediate-ios-get-job-ready-with-swift-2/ Tue, 12 Jul 2016 12:35:22 +0000 https://swiftludus.org/?p=1811 Read more]]> You have dipped your toes into the water of iOS development and you want to go beyond the basics of making simple iPhone apps. You are ready to move on, move forward, and escalate your capabilities. You want to build amazing apps that impress and results in career opportunities with increased earning potential.

You are ready for the advanced iOS development class that teaches the most advanced iOS topics available, while coaching you through building your career in iOS development. Learn about In-App Purchases, Localization, Drawing in iOS, Push Notifications and more.

Access this course on Zenva Academy

]]>
Working with Closures in Swift https://gamedevacademy.org/closures-tutorial-2/ Mon, 16 May 2016 12:00:05 +0000 http://104.131.83.156/?p=1571 Read more]]> Closures

Closures are small, self-contained blocks of code that can be used in our code, not unlike a function. (The reason these are called closures is because they’re said to “close” over constants and variables.) Let’s first get some context for closures. Suppose we have an array of names that we want to sort. Well it turns out that all arrays have a sorting function that we call and pass in a function that the sorting function will use to sort the names depending on the function parameter. Really, we have two sorting functions: one that sorts and returns the sorted array, or one that does the sort in-place. This means that the sorting will modify the original array.

var names = ["Louis", "Ella", "Bill", "Freddie", "Sammy", "Kermit"]

func alphabetical(_ s1: String, _ s2: String) -> Bool {
    return s1 < s2
}

names.sort(by: alphabetical)

The sorting function requires a function whose parameters are strings and returns a boolean. That boolean should be true if the first parameter comes before the second. However, this seems like a lot of work for a really simple task! We can put the function “in-place” in a sense by using closures in place of the function when we pass it into the sorting function.

names.sort(by: {(s1: String, s2: String) -> Bool in return s1 < s2})

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

Closures are contained in a set of braces. Any input parameters come first, surrounded in parentheses. Then comes the return arrow and a return type, if any. Then comes the in  keyword and the body of the closure. Essentially, we just copy-and-pasted the function body into the body of the closure.

However, we can make this even shorter by remembering that Swift can infer the type of the parameters and return type. The sorting function requires that the function passed in to take two strings, in this case, and return a boolean. Because of Swift’s type inference, we can get rid of the type annotations and return type from the closure. As a byproduct of this, we can also get rid of the parentheses of around the parameters.

names.sort(by: {(s1, s2) in return s1 < s2})

This even simpler than before! However, Swift can make this even simpler! Notice how our statement body is really just a single return  statement. There’s no ambiguity in this so we can omit the return  keyword.

names.sort(by: {(s1, s2) in s1 < s2})

Swift keeps making this simpler! But we’re not done yet! Swift assigns each parameter a zero-index variable like $0, $1, $2, $3, and so on for each parameter. In our case, we only have two parameters. We can use the Swift-assigned variables instead of our own to make our closure even sorter. Since our closure just has the closure body, we can omit the in  keyword as well.

names.sort(by: {$0 < $1})

We’re almost finished, but not quite! Swift strings have a specific implementation of the comparison operators, such as less-than, greater-than, equal-to, etc. In Swift, we can actually define our own operators for our particular objects, but that’s beyond the scope of this material. Instead of using the parameter names, we can very simply pass in the less-than operator and Swift will automatically infer that we want to compare the strings using the string implementation of the less-than operator.

names.sort(by: <)

This is still the second-shortest way to write this function! As it turns out, the default implementation of the sorting function will automatically assume alphabetical order so we can simply this down to a single function call with no parameters: names.sort() .

Trailing Closures

When using complicated closures in functions, it might be cleaner to write the closure as a trailing closure instead. This allows us to write the closure outside of the function call. We can only do this if the closure is the final argument, and it’s good practice to put a closure as the last parameter for this exact reason. Take the following function that takes a seed and a closure and performs an operation on a random number. We need to seed the pseudo-random number generator with a seed so that it doesn’t generate the same pseudo-random number each time. Usually we’d use the time, but we’ll just pick a number for now.

func opOnRandNum(_ seed: Int, closure: (Double) -> Double) {
    closure(Double(seed) + 17)
}

opOnRandNum(20, closure: {(num: Double) -> Double in
    var result = (num + 293) * 7
    return result - 45
})

opOnRandNum(25) {(num: Double) -> Double in
    var result = (num + 293) * 7
    return result - 45
}

The first call of the function doesn’t use a trailing closure, and we can see that since we have the external parameter label on the closure and the entire closure is inside of the parentheses of the function. The second time we call the function, we use a trailing closure. Notice how we appear to call the function with the first parameter, then we put the closure after the function call. This makes our code look much cleaner. We could actually use some of the type inference techniques we learned in the previous subsection to shorten this closure even more.

In this section, we learned about what closures are and how we can use them in our code as an alternative to very short  functions. We also used Swift’s type inference to reduce the complexity of the closure and write it in the shortest, clearest way possible. We also learned how to use trailing closures to put the closure body after the function call to make the call look cleaner.

Enumerations

An enumeration, or enum for short, is a collection of related values that we can use in a very type-safe way. For example, suppose we wanted to represent the planets somehow. We could declare integer constants for all of the planets from 1 to 8. But what if the user accidentally inputs something not in [1, 8]? Then we have to add additional error checking and this quickly becomes tedious to do a simple task: represent the planets. Enums gives us a type-safe way to do this. Let’s take a look at how.

enum Planet: Int {
    case mercury = 1
    case venus
    case earth
    case mars
    case jupiter
    case saturn
    case uranus
    case neptune
}

var home = Planet.earth
home = .mars

Above, we declare an enum with a name and several cases, or constants. Now we can create a variable and assign it to one of the constants. After we first assign the enum variable to a value for the first time, that variable can only takes values of that enum. In the last line, we change the variable, but we can only do so to another value in the same enum. As a result of this inference, we can drop the enum name and just type in a period (.) and the value.

Enums become especially useful when using them in a switch statement. Since Swift knows that the variable can only take values of a particular enum, we can drop the enum name in the case declarations, much like when we reassigned the variable above.

switch home {
case .earth:
    print("No place like home!")
case .mars:
    print("Future home maybe?")
default:
    print("Better not venture there!")
}

Though it might not look like it, this switch statement is exhaustive since our enum has a finite amount of values. Every other enum value that we didn’t have a specific case for will be in the default case.

Associated Values

Enums can not only store values, but those values can store values as well! Enums can store associated values along with the case values so that we can compact more information into an enum. Let’s think about this using an example. PNG and JPEG are two of the most widely used image formats. PNG is a lossless image format, and JPEG is a lossy image format, meaning that some image data is lost when compressing the image. Each image can have a resolution, but the JPEG should have some quality metric that tells us how lossy this image is. It would be nice if we could store information on both in case we’re converting formats. We can do exactly this with associated values.

enum Image {
    case PNG(Int)
    case JPEG(Double, Int)
}

var canihazcat = Image.PNG(1024)
canihazcat = .JPEG(1.0, 600)

The first case has an associated value of just an Int and the second has an associated value of (Double, Int). Now we can create an enum variable of a particular case and associated value. Now suppose we converted that image into a JPEG. Well we can reassign the value of the variable and the associated value. After the last line in the above snippet, the variable will fall under the case of JPEG with associated values (1.0, 600) instead of a PNG with an associated value of 1024.

We can use this with switch statements and value binding to extract those associated values. The associated values we want to extract come in parentheses with variable after the case value we’re checking for, like the following code snippet.

switch canihazcat {
case .PNG(let res):
    print("PNG with resolution \(res)ppi")
case .JPEG(let quality, let res):
    print("JPEG with \(quality*100)% quality and resolution \(res)ppi")
}

switch canihazcat {
case let .PNG(res):
    print("PNG with resolution \(res)ppi")
case let .JPEG(quality, res):
    print("JPEG with \(quality*100)% quality and resolution \(res)ppi")
}

The second switch statement is a shorthand to the first. If we’re planning on extracting all of the values, we can simply put a single let  keyword right after the case  keyword.

Raw Values

Associated values are great, but what if we want something simpler and more automatic? We can automatically assign each enum value a raw value. Every raw value must be of the same type, but we can access it and actually use it to help initialize a value. Let’s go back to our planet example.

enum Planet: Int {
    case mercury = 1
    case venus
    case earth
    case mars
    case jupiter
    case saturn
    case uranus
    case neptune
}

var homeID = Planet.earth.rawValue

To assign each enum value a raw value, we must give a “type annotation” to the enum and assign the first case value a raw value corresponding with the raw value annotation. All of the subsequent values will be assumed to go in order according to the value on the first case. We can get the actual name of the enum value by letting the raw value annotation to be of type String and Swift will infer that the raw value is the actual name of the case.

enum Planet: String {
    case mercury
    case venus
    case earth
    case mars
    case jupiter
    case saturn
    case uranus
    case neptune
}

var homeName = Planet.earth.rawValue

The raw value of Earth will now be “Earth”. We can go a step further and use the raw value to help initialize a planet. However, the associated value we provide might not be in the range, so we could get a nil value back. This is where optionals and value-binding come in handy!

var possiblePlanet = Planet(rawValue: 9)
if let pluto = possiblePlanet {
    print("Found a planet!")
} else {
    print("Pluto is not a planet anymore!")
}

To initialize a planet based on a raw value, we use the name of the enum and pass in the raw value. This returns an optional of the same type as the enum. Then we have to use value binding to see if this variable is not nil.

In this section, we learned about enumerations and how we can use them with switch statements. Enums are just collections of related values. We can assign each case value its own associated values to store more information in a case. We can also automatically assign enum cases raw values all of the same type.

]]>
Swift Tutorial 6 – How to Use Functions in Swift https://gamedevacademy.org/swift-tutorial-6-how-to-use-functions-in-swift-2/ Tue, 19 Apr 2016 12:00:45 +0000 http://104.131.83.156/?p=1560 Read more]]> In this post, we’re going to learn about how to define and call various types of Swift functions. A function is a self-contained block of code whose purpose is to perform a specific task. We use functions so that we can break up the main source code into manageable chunks. Also, if we need to repeat code, we can simply call the function instead of copying-and-pasting the code.

Functions have 3 main parts: the function name, any input parameters, and any return type. All functions need names, but not all need any input parameters or need to return a value. In fact, we’ve actually been using functions this entire time! The print(…)  function that allows us to print to the preview pane is a function that takes parameters and doesn’t return anything. We’re going to see how we can declare and use functions with parameters and a return type; we’ll also learn some Swift shorthand and extra functionality that Swift provides over other programming languages.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

Functions without Return Types or Parameters

Also called procedures, we can declare a function with no input parameters or return like the following.

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

printHello()

First comes the keyword func  and then the name of the function. Afterwards, any input parameters will come after in the parentheses, but we don’t have any. Then comes the function body in a set of curly braces. In the last line, we call the function, and it will execute the code. Now that we have this function, we can call it as many times as needed and the same block of code will execute.

Functions with Parameters

Inside of the parentheses, we can declare any number of parameters that we can pass to the function. Take the following function, for example.

func sayHi(_ firstName: String, lastName: String) {
    print("Hi " + firstName + " " + lastName + "!")
}

sayHi("Bob", lastName:"Smith")

In the parentheses, we have a comma-separated list of input parameters to the function. Each one needs a parameter name so we can refer to them inside of the function, and each one needs a type annotation as well. After declaring these parameters, we can use them in the function. We can call the function and supply in the input parameters. Note that the first parameter can just be passed through a literal or variable, but every subsequent parameter needs to be labeled using the parameter name in the function declaration. This is where Xcode will help by automatically filling in those parameter names. We’ll discuss these parameter names a bit later in this section.

Functions with Return Types

Functions can return values as well as take in input. Consider the following squaring function.

func squareNum(_ x: Double) -> Double {
    return x * x;
}

print(squareNum(10))

We can specify a return type by putting the return arrow (->) after the parentheses and specifying a return type. This means that somewhere in the function, usually at the end, we need to say return  and then some value that corresponds to the type we’re returning. When we call this function, we can set the return value to a variable or we can ignore it altogether.

Swift also supports returning multiple values in the form of tuples. We can change the type after the return arrow to be a tuple. The tuple follows all of the characteristics of Swift tuple, including naming the tuple values. Take the following square root function.

func squareRoot(_ x: Double) -> (positiveSqrt: Double, negativeSqrt: Double) {
    let posSqrt = sqrt(fabs(x))
    let negSqrt = -sqrt(fabs(x))
    return (posSqrt, negSqrt)
}

print(squareRoot(25))

In this function, we’re returning a tuple that has two fields, both being Doubles and named. We don’t have to name the tuple members, but it’s good practice to do so we don’t have to refer to them through indices. In addition to these tuple types, we can even have optional tuples whose value with can check using value binding. Here’s an example of how we can return optional tuples.

func squareRoot(_ x: Double) -> (positiveSqrt: Double, negativeSqrt: Double)? {
    if x < 0 { return nil }
    let posSqrt = sqrt(fabs(x))
    let negSqrt = -sqrt(fabs(x))
    return (posSqrt, negSqrt)
}

if let val = squareRoot(25) {
    print(squareRoot(25)!)
}

Notice how there is a question mark at the end of the return tuple when declaring the function. Since it returns an optional, we now have to use value binding when dealing with the return type since it’s not guaranteed to be non-nil.

Function Parameters

We saw in a previous example how to use functions with multiple parameters. In this subsection, we’re going to expand on the different things we can do with function parameters.

External Parameter Names

In the example on multiple parameters, note how we had to label each input with the parameter name starting with the second parameter. We can change the parameter names so that they make more sense to someone calling the method while retaining our name context for the parameter.

func sayHi(person personToSayHiTo: String, times numTimes: Int) {
    for var i = 0; i < numTimes; i++ {
        print("Hi " + personToSayHiTo + "!")
    }
}

sayHi(person: "Bob", times: 3)

As a side note, giving the first parameter a name will force the caller of our function to use that external parameter name instead of just passing in the input. We’ll talk more about removing this label in the next subsection. Anyway, as we can see above, the first name is the external name of the parameter while the second name is the internal name, used inside the function. When we call the function, we can use the external names instead of the internal names. This allows us to separate the two different contexts: implementer of the function and caller of the function.

Omitting External Parameter Names

One issue with the last code snippet was that we had to label the input with the external parameter name. Even in the first code snippet with multiple parameters, we have to label the inputs starting with the second parameter. Using parameter names is a good practice, but it in some contexts, it might be unnecessary because the function and its parameters are intuitive enough for callers to understand. We can allow our user to skip the labeling if we substitute an underscore (_) for the external parameter name. For example, take the following function. We need to always provide an external label or an underscore.

func doublePower(_ base: Double, _ exponent: Double) -> Double {
    return pow(base, exponent * exponent)
}

print(doublePower(2, 2))

Note that we don’t have to do this for the first parameter since it doesn’t require a label by default. Now that we don’t need to label the second parameter, we can just pass in the value directly.

Default Parameter Values

For any parameter, we can give it a default value by assigning the parameter a value in the parentheses right after the parameter type. If a function’s parameter has a default value, we can omit that parameter when calling the function.

func doublePower(_ base: Double, _ exponent: Double = 2) -> Double {
    return pow(base, exponent * exponent)
}

print(doublePower(2))

As a point of good practice, it’s a good idea to put all of the parameters with default values at the end of the parameter list so that callers of our function start off with the same format for the parameters without default values.

It is very important to note that ANY CHANGES MADE TO A VARIABLE PARAMETER IN THE FUNCTION DO NOT PERSIST! This means that if we were to modify the variable parameter, it wouldn’t alter the original variable that the caller passed into the function. However, there is a different way we can solve this problem, as illustrated in the next section.

Parameter References

Swift does provide us a way to allow changes to parameters to persist even after the function is called. A classic example is a function to swap the value of two variable. Beginning programmers will try to write a swap function that swaps values but forget that copies of the variables are made when a function is called. Those changes don’t persist! However, we can pass in the parameter references so that that changes will persist after the function call. To do this, we must add the inout  modifier to the function parameter declaration.

func swap(_ x: inout Int, _ y: inout Int) {
    let temp = x;
    x = y
    y = temp
}

var a = 3
var b = 4
swap(&a, &b)

In the above code, by saying that the parameters are inout , we’re allowed to modify the variables directly, not just copies! When we’re passing values into a function that has inout parameters, we need to use ampersands (&) so that the caller of the function, us in this case, knows that the function will modify the variables directly. Now we can see that the variable’s values have been successfully swapped!

Functions as Types

Each function that we define has a “type” or signature that is the combination of the input parameters and return type. Swift allows us to use this property of functions to define variables that represent functions. Let’s see an example of this to make the concept clearer.

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

func subtractInts(_ x: Int, _ y: Int) -> Int {
    return x - y
}

var mathOp: (Int, Int) -> Int = addInts
mathOp(3, 4)
mathOp = subtractInts
mathOp(3, 4)

In the above code snippet, we declare two functions with the same signature. Next we have a variable that we set to a function! The type of the variable is “a function that takes two integers and returns an integer”. After we assign this variable, it essentially acts as an alias to the function it’s assigned to! We can change this variable to be another function, subtractInts, and when we “call” the variable, it will route to subtractInts instead. Swift treats functions as first-class variables so we can use them as parameters and return types as we’re going to see.

We can use a function as a parameter by using the signature as the type annotation as seen in the function below. We’re saying that the parameter is a function that is guaranteed to take two integers and return an integer.

func executeMathFunc(_ mathOp: (Int, Int) -> Int, _ x: Int, _ y: Int) -> Int {
    return mathOp(x, y)
}

print (executeMathFunc(addInts, 3, 4))

Now we can treat it as a function and pass it the input values. This allows us to pass in any function that takes two integers and returns an integer. We can also use functions as return types of other functions.

func chooseAddSub(_ add: Bool) -> (Int, Int) -> Int {
    return add ? addInts : subtractInts
}

var getFunc = chooseAddSub(true)
print(getFunc(1, 2))

The above code has a function that returns a function! Don’t get confused by the arrows, though. The first arrow is the return type of the function and the second tells us that the returned function is guaranteed to return an integer.

To recap, in this section, we learned all about functions. We saw how to give functions multiple parameters as well as a return type. We also saw how to name external parameters and the various modifications we can add to parameters to allows us to modify those parameters. Finally, we learned how to use functions as variables, both as parameters and return types of other functions.

]]>
Swift Tutorial 5 – How to Use Control Flow in Swift https://gamedevacademy.org/swift-tutorial-5-how-to-use-control-flow-in-swift-2/ Tue, 12 Apr 2016 12:00:44 +0000 http://104.131.83.156/?p=1556 Read more]]> In this section we’re going to look at the various looping constructs and decision statements that Swift supports. We’ll be learning about while, repeat-while, and the variations of for loops. Next, we’ll discuss decision statements such as the if, if-else, and switch case statements. Finally, we’ll finish this section by talking about the branching statements we can use to control the program flow.

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.

Looping Constructs

While Loops

The simplest kind of loop is called the while loop. This loop will simply run until the given condition is false. Let’s look at the following code snippet.

var counter = 0
while counter < 5 {
    print("Counter is at \(counter)")
    counter += 1
}

There are a few things to understand about this loop here. In the case of the while loop, the loop’s condition is check before the loop’s body is executed at every iteration, including the first iteration! For example, if the loop’s condition was counter < -1 , the loop wouldn’t execute at all. Also note that the loop does iterate 5 times, but the last value of the counter is 4. Outside of the loop, the counter will be 5, but the last valid iteration, just before the loop is terminated, the counter is at 4. Simply put, this while loop will execute forever until the condition is false.

Repeat-While

A repeat-while loop is almost exactly like a while loop, except with one key addition: the loop’s condition is checked at the end! This guarantees the loop will iterate at least once! Take the following code snippet.

var counter = 0
repeat {
    print("Counter is at \(counter)")
    counter += 1
} while counter < -1

The condition is not met, but the loop will still execute once, then terminate. This type of loop is particularly useful when we need to do any sort of input validation such as the following.

var input = -1
repeat {
    print("Please enter a valid input (1 - 100): ")
    input = getInputFromProgramSomehow()
} while input <= 0 || input > 100

The above loop will run the prompt until the user enters a valid input.

For-in Loops

Swift offers a sophisticated for-in loop that can be used to iterate through a range, an array, a set, a dictionary, a collection of tuples, and many other structures. In previous sections, particularly the Collection Types section, we’ve seen how to use for-in loops to iterate over an array, set, and dictionary so look back at that section for example on how to do that. Let’s see how we can iterate through the numbers 1 to 5 as a for-in loop.

for counter in 1...5 {
    print("Counter: \(counter)")
}

This loop will run 5 times, but, as we can see from the use of the closed range operator, the counter values will be 1, 2, 3, 4, 5 and not 0, 1, 2, 3, 4. We could easily fix this by changing the in clause to say 0..<5  instead. Also note how we don’t need to declare our counter variable before it’s used like we did with the for loops. The reason for this is that Swift will implicitly declare the the counter to be a constant that iterates through the values of the range, so we don’t need to declare the counter with an explicit var  or let .

There might be some cases where the counter variable itself is unnecessary and so we don’t want to create a variable name for it.

for _ in 1...5 {
    print("Hi!")
}

This is easily fixed, as shown in the above snippet, by replacing the variable name with an underscore (_).

To recap this subsection, we discussed the 3 major types of loops that Swift offers: while, repeat-while, and for-in. The while loop will execute until the condition is false. The repeat-while loop will do the same, except check the condition at the end. The versatile for-in loop can be applied to ranges, arrays, sets, dictionaries, and other structures.

Decision Statements

If and If-Else

The simplest decision statement is the if statement. It will simply execute a block of code if the condition is true.

var heartRate = 75
if heartRate <= 80 {
    print("Relaxing")
}

The above code will print “Relaxing” since the condition is met. Keep in mind that the condition can be any boolean expression that evaluates to true. We can use any of our conditional operators to create a resulting boolean. In addition, we can add an else block that executes if the condition is false.

var heartRate = 100
if heartRate <= 80 {
    print("Relaxing")
} else {
    print("Exercising")
}

Now the else block will execute since our condition was not met. We can have multiple cases by using else-if blocks in case we have several bands of values we have separate code for.

var heartRate = 100
if heartRate <= 80 {
    print("Relaxing")
} else if heartRate > 120 {
    print("Get help!")
} else {
    print("Exercising")
}

One important thing to note is that Swift will only execute the first block of code whose condition is met. This means that the order in which you put the else-if blocks does matter in some cases.

Switch

A switch statement operates on a value and executes code if it matches a pattern. We can match a single possible value or multiple values. However, the switch statement must be exhaustive, meaning that every possible value of the operand must be a case. In the event of any number type, we obviously can’t account for every possible value, so we can use a default case that’s execute if none of the other cases match.

let number:UInt = 1;
switch number {
case 0:
    print("Number is zero!")
case 1, 3, 5, 7, 9:
    print("Number is odd!")
case 2, 4, 6, 8, 10:
    print("Number is even!")
default:
    print("Number is bigger than 10!")
}

It’s important to note that only the code in the matching case is executed, no other cases are executed. In addition to matching specific values, we can also use the switch statement to match intervals.

let number:UInt = 1234;
switch number {
case 0..<10:
    print("Number is less than 10!")
case 10..<100:
    print("Number is less than 100!")
case 100..<1000:
    print("Number is less than 1000!")
default:
    print("Number is bigger than 1000!")
}

We’re using the range operators to define intervals that we can match if the number falls in one of those intervals. In addition to intervals, we can also match tuples. However, since tuples can have many different values, we can use the underscore (_)  as a wildcard to match anything.

let point = (0, 0)
switch point {
case (0, 0):
    print("Point is the origin")
case (_, 0):
    print("\(point.0) is on the x-axis")
case (0, _):
    print("\(point.1) is on the y-axis")
case (0...1, 0...1):
    print("(\(point.0), \(point.1)) is inside the unit box")
default:
    print("Point is outside the unit box")
}

In the above code, we’re using the underscore to tell Swift that this part of the tuple can take on any value. In the final case, we’re using the range operators inside the tuple. We can refer to the coordinates using the dot notation and it’s position in the tuple, but we can use value binding in a switch case to assign the underscore to an actual value we can use.

let point = (0, 0)
switch point {
case (0, 0):
    print("Point is the origin")
case (let x, 0):
    print("\(x) is on the x-axis")
case (0, let y):
    print("\(y) is on the y-axis")
case (0...1, 0...1):
    print("(\(point.0), \(point.1)) is inside the unit box")
case let(x, y):
    print("(\(x), \(y)) is outside the unit box")
}

In the above code, we’re using value binding to assign values to those underscores so we can use them in the case statement. To make switch statements even more powerful, we can use a where clause to add additional constraints.

let point = (0, 0)
switch point {
case let (x, y) where x == y:
    print("(\(x),\(y)) is on the line y = x")
case let (x, y):
    print("(\(x),\(y)) is some point in 2D space")
}

In the above code snippet, we’re adding the constraint that x must be equal to y in order to execute the code in this case.

To recap this subsection, we learned about the elementary decision structures we can use to execute code conditionally. If and else-if will execute code only if a particular condition is met. The same is true for the switch case, except switch case is more powerful with its value bindings and and where clause.

Branching Statements

Continue

This branching statement will skip over the current iteration of the loop. Any code after the statement will be skipped for this iteration. The loop will “continue” at the next iteration.

for index in 0...100 {
    if index % 3 == 0 {
        continue
    }
    print("\(index)")
}

The above code will skip over all numbers that are divisible by 3.

Break

The break statement, when used in a loop, will terminate the closest loop to it. If we had two nested loops and the break statement was in the innermost one, then that would be the loop that would terminate, but the outermost loop would still run. In a switch statement, we can use it to disregard a particular case.

var num:UInt = 3
switch num {
case 1:
    print("One")
case 2:
    print("Two")
default:
    break
}
print("Outside switch")

In the above code, we don’t want anything to happen in the default case, so let’s break out of the switch case. Leaving the default case blank would be a syntax error, so we use the break statement.

Fallthrough

Remember that only one case in a switch statement is executed. Suppose we wanted to fall through to the next case, we can do just this by using the fallthrough statement as the final statement in the case we’re initiating the falling through.

var num:UInt = 1
switch num {
case 1:
    print("One")
    fallthrough
case 2:
    print("Two")
default:
    break
}
print("Outside switch")

In the above example, case 1 will execute and so will case 2 since we have the fallthrough statement at the end of the first case.

In this section, we’ve covered all of the different looping constructs and decision control statements. We also learned how we can manipulate program control flow using the branching statements.

]]>