Lecture Handout
Welcome
Hello! Welcome to AppDev’s iOS Training Course. Throughout this course, you will learn all the fundamentals of iOS programming and learn how to build your own full-fledged iOS applications! Each lecture will be accompanied by a handout (like this) summarizing the main concepts from that lecture. This is the first handout and we will be covering Swift and Xcode.
Xcode
What is Xcode?
Xcode is the main integrated development environment (IDE) that iOS developers use to develop their applications. In simpler terms, Xcode is just the application that we use to write iOS code (similar to how you might use Atom, Sublime, vim, etc.). The reason all iOS developers use Xcode (instead of other IDE’s) is that other than being a place for us to write iOS code, Xcode allows us to run our code and build our application on a simulator. This is important because otherwise we would have no way to testing if our code actually does what it wants!
Creating a new Xcode project
Setting Up a New Xcode ProjectSwift
What is Swift?
Swift is Apple’s newest programming language for developing iOS applications. One other popular programming language that you can use is Objective-C. However, in this course we will be using Swift. Thus, you will be writing Swift code inside your Xcode project and then running that on the simulator to see your application come to life.
Swift Basics
We will now cover some fundamentals of the Swift programming language. One thing to note is that while we will not be able to cover every single aspect of Swift in this handout, any aspect not covered can be found through a simple Google search.
Variables and Constants
Like other programming languages, we can declare a variable in Swift using the syntax var [variable name] = [value]
.
Unlike languages like Java, where value types have to be explicitly typed, Swift has type-inferencing so Swift is able to infer the type of your variable based on the value that you assign to it. For example, by assigning 5 to x
, Xcode knows that x
is of type Int because 5 is of type Int. Therefore, when declaring a new variable and assign a value to it, it is not required to also declare the type of the variable.
If you wanted to, however, you could do so using the syntax var [variable name]: [type] = [value]
There are also some cases where the type is ambiguous and Swift cannot automatically infer the type so you'd have to explicitly declare the type for the compiler.
In addition to variables, we can also declare a constant. One important distinction to make between variables and constants is that after you assign a value to a constant, you cannot change the constant’s value again in the future (you can change a variable’s value). The syntax to declare a constant is let [variable name] = [value]
. Similar to variables, it is not required to declare the type of the constant, although you can.
Classes and Structs
In Swift, we can also declare classes and structs. Every class contains several different parts: a class name, fields, and methods. Fields are just variables/constants that belong to that class. In our sample class above, for example, our Song class contains a name
field of type String
and an author
field of type String
. Similarly, methods are just functions that belong to that class. In our example above, we have an init method which is called when you create an instance of that class.
A struct has the same exact syntax as a class (except you replace class with struct). However, a core difference between structs and classes is that structs are value types whereas classes are reference types. What does this mean? A value type “is a type whose value is copied when it’s assigned to a variable or constant, or when it’s passed to a function.” On the other hand, reference types “are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used.” To see what this means, let us look at the following example.
Using the Song class that we declared before, we create an object of type Song and assign variable songA
to that Song object. Next, we create another variable songB
and assign its value to be songA
. Then, we set the name
field of songB
to be “Walk on Water” (previously was “Lucky You”). Lastly, we print the value of songA
’s name
field and the value of songB
’s name
field. In both cases, “Walk on Water” gets printed.
Why does this happen? Well, because Song is a class and we know that classes are reference types, when we created our new Song object and assigned that to songA
, what really happened is that songA
’s value was a pointer to that Song object. Then, when we assigned songA
to songB
, what we were doing was assigning songB
that exact same pointer. Thus, when I changed the value of songB
’s name field, we actually altered the object that both songA
and songB
were pointing to, and thus the value of songA
’s name field changed as well.
If instead Song was a struct, we would see something else happen:
Looking at the example above, we see that printing out songA
’s name
prints out “Lucky You” and printing out songB
’s name
prints out “Walk on Water” (unlike the previous case where they both printed out “Walk on Water”). Why did this happen? Well, remember that structs are value types. Thus, when songA
was assigned to songB
, a copy of the Song object that songA
was pointing to was passed to songB
(unlike the previous case where the pointer to the exact same Song object was passed to songB
). Thus, when we changed songB
’s name field, songA
’s name field was not changed because songA
and songB
are pointing to two different Song objects.
Optionals
In Swift, we also have a type that you may not often see in other programming languages, optionals. Optional types just mean that a variable may hold some value or it may not (i.e. it is nil
). For example, let's consider a situation where we want to look at assignment grades for a student.
What if the TA hasn't graded assignment 3 for the student yet? How do we represent that grade3
might not actually have an integer value? Well, this is where optionals come in.
By making this change, we have redeclared grade1
, grade2
, and grade3
to be variables of an optional Int type so that it is possible for any of these variables to actually be nil, for the case when the TA has not yet provided a grade. In the example above, after the TA provides grades to assignment 1 and assignment 3, grade1
and grade2
will now have integer values. However, grade3
will still hold a nil
value.
Now suppose we want to print out the grades for the student.
Trying to print grade2
will cause an error because grade2
could potentially be nil
. In order to actually use this variable, we have to first unwrap the value inside the variable and check if it actualyl has a value. There are two main ways to unwrap a variable: using an if-let
statement and using an guard-let
statement. First, let's take a look at unwrapping using an if-let statement:
The syntax for an if-let
statement is if let [unwrapped constant name] = [optional variable] { … } else { … }
. In our example above, we take optional variable grade2
and then we try to unwrap it. If grade2
actually does hold some value, then that value gets assigned to the constant unwrappedGrade2
and then we enter the first block of code. If, however, grade2
was nil
, the second block would get run.
Another way that you can unwrap a value is using guard-let.
The syntax for a guard-let
statement is guard let [unwrapped constant name] = [optional variable] else {…}
. In our example above, we take optional variable grade2
and then we try to unwrap it. If grade2
actually does hold some value, then the rest of our code runs under the assumption that the new unwrappedGrade2
holds that value and grade2
is still an optional. If, however, grade2
was nil, the else block will get run. One thing to take note when using guard-let
statements is that in the else-block, you must either return or throw some error at the end of it. This aspect is what distinguishes it from an if-let
.
We often use guard-let
statements more for cases where you want to assume an optional variable is non-nil for that portion of the code, and if not, then we want to exit or throw the proper error. if-let
statements are better for cases where either nil
or a real value is fine, we just need separate cases to handle each one.
Last updated