Lecture 1 - MVC, Swift, and Xcode

Welcome to Introduction to iOS Development! In this first lecture we will explore Swift, the primary language we will use to develop iOS apps, and Xcode, the IDE you will be using to write, compile, and run these applications.

Download the lecture slides here.

Swift

Swift is an object-oriented, functional programming language designed by Apple and released in June 2014. It is one of two languages you can use to make iOS apps (the other being Objective-C, which we will not cover in this class), and it is the cleaner and more reasonable of the two languages (which is why we're choosing to work with it).

We'll start with the very basics of Swift. It's a good idea to check out The Swift Programming Language by Apple as a general guide to everything in this lecture.

Variables and Constants

In Swift, you can declare variables (you should know what these are) and constants (values that cannot be changed). You use the var keyword to define a variable and the let keyword to define a constant, as follows:

var someVariable: Int = 6
var someBool: Bool = true
// The following cannot be changed:
let someConstantString: String = "I'M A CONSTANT"
let PI: Float = 3.14

Swift Types

Swift has several built-in types, such as Int, UInt, Float, Double, Bool, and String. In addition, Swift supports arrays of types, simply by wrapping the type with brackets (so, an Int array is represented as [Int]).

Swift allows you to specify the type of a variable or constant when you declare (as exactly shown above), but it is not required. So, you can declare variables and constants like so:

var someIntArray: [Int] = [1, 2, 3]
var whatTypeAmI = 1.2
let someStringArray: [String] = ["I'm", "an", "array"]
let callMeTypeless = true

For style reasons, you should always declare variables and constants with their types. It helps you type-check your code and makes it more readable (functional programmers and type theorists rejoice).

For the most part, you can cast one variable type to another type, simply by treating the target type as a function (it's actually a constructor, because everything is a class, but we won't get into that just yet). What does this mean? Here's some examples:

var someInt: Int = 5
var someUInt = UInt(someInt)     // still 5, but now it's unsigned!
var someString = String(someInt) // now "5"

Notice how we omitted some of the variable types; this is because it's painfully obvious what type someUInt and someString are going to be, based on their assignments.

Functions

Swift's function syntax is extremely simple:

// Returns the input, multiplied by 7.
func timesSeven(i: Int) -> Int {
    return i * 7
}

Notice how you specify the inputs and outputs. For void functions, (functions that don't return anything), you don't need the arrow (->) syntax:

// Does nothing!
func doNothing() {
    var i: Int = 2
    ++i
}

In addition, you can specify external parameter names. These are parameters names that are visible to, and required by, the caller. What does this mean or look like? Suppose you have code like this:

func addUserInfo(...) {
  ...   // implementation here
}

...

addUserInfo("Mike", 20, 2005, -150000, "Burgers & Fries")

It is extremely unapparent what all of those numbers and strings mean in the call to addUserInfo! You may be able to infer some information, but definitely not all of it. Swift fixes this problem with external parameter names. The function can specify these names, and thus force the caller to make a call like this:

addUserInfo(name: "Mike", ageInYears: 20, yearOfCurrentCar: 2005,
            netWorthInDollars: -100000, favoriteFood: "Burgers & Fries")

Now we know what we're talking about! External parameter names are just extra labels tacked on to function parameters to help the programmer understand he code a bit better. However, its usage is a little bit confusing. To specify this on a function that you're writing, you would use this syntax:

func funcName(externParamName localParamName: ParamType, ...) { ... }

So, for the above example, it might look like:

func addUserInfo(name _name: String, age _age: UInt, 
                 yearOfCurrentCar _yearOfCurrentCar: UInt,
                 netWorthInDollars _netWorthInDollars: UInt,
                 favoriteFood _favoriteFood: String) {
    println(_favoriteFood)  // example usage
    ...                     // rest of the function body.
}

Pretty verbose, right? Everything has two names here, an external name, and a local name. You would use the local name (in the above example, the names prepended with underscores) in your function body, and not the external one.

Note that we prepended some underscores to the external names to show a difference with the local names. In theory, you could name the external and the local name the same, as such:

func addUserInfo(name name: String, age age: UInt, ...) {
    println(name)  // example
    ...
}

However, Swift has shorthand for this type of thing, and so you'll commonly see this syntax used around:

func addUserInfo(#name: String, #age: UInt, ...) {
    println(name)  // example
    ...
}
    

In general though, use external parameter names (almost always the hashtag syntax above), unless it's apparent what the parameters are (i.e., it's easily inferrable by just looking at a function call).

Optionals

Swift supports optionals! If you've taken 15-150, you know what they are already. Optionals give a unified null value to all types. It's used just like you would return a null pointer in a function: it signifies that there is no value or no result.

To specify that a value is optional, just postpend its type with ?, like this:

var n: Int? = nil
var m: Int? = 2
var q: Int?  // equivalent to nil!

So, n, m, and q are all optional Ints: this means they can either be an integer, or they can be nil, which is the Swift keyword for a null value. To use these values, you unwrap them with the postpend !. The general pattern of use is as follows:

// Returns a divided by b.
func divide(dividend a: Float, divisor b: Float) -> Float? {
  if (b == 0) {
    return nil
  }
  return a / b
}

var result: Float?
var printStr: String
result = divide(dividend: 2, divisor: 0)
if (result != nil) {
  printStr = "Success! The result is \(result!)"
} else {
  printStr = "Failure!"
}

println(printStr)

Whoa, okay, so that might've been a lot. Let's break it down. We've defined divide, which is a function that takes in two floats and returns a float optional; you should be able to figure out when divide returns nil and when it doesn't. Then, we check the value with a simple if statement. In line 13, we unwrap the value of the optional result with an exclamation mark (!). The exclamation mark basically says, "Hey, I know this optional isn't nil, so just give me the value, kthx." Your app will crash if you try to unwrap a nil value, so always be sure to check!

In addition, you've seen some of the basic control flow of Swift (if and else), and you've seen the built-in function println, which simply prints to the console. One last thing to note is syntax for converting variables in-string, which you'll see as \(varname). This converts the variable inside to a string (and also inserts it in that spot inside the string).

So, which string gets printed? It'll be "Failure!", because divide will return nil.

Emoji's and Other Non-ASCII Characters

Swift supports UTF-8/Emoji's/etc. in code. Now if you want to use the constant pi (3.14) in your code, you can use an actual Greek pi symbol! You can even name a variable by a smiley-face!

Do NOT freaking do this. Use ASCII only. If you name a variable by a smiley-face or a kitty-cat, you lose everyone's respect for you as a programmer. Your grandmother would be very disappointed in you.

Object-Oriented Programming

You should already know what an object is, but if you need a refresher: an object is something we use in code to represent an object we might find in real life. For example, if I wanted to represent a bank account, I could create an BankAccount class which would contain attributes like a account owner name (String), PIN (String or Int), account balance (Float), etc. To create bank accounts, we would need to write an BankAccount class. A class is like a blueprint for creating objects. Each instance of the BankAccount class contains the properties of a specific bank account.

Using Instances

Let's create a new instance of the BankAccount class we talked about earlier. It would look something like this:

var someBankAccount: BankAccount = BankAccount()

We have to go to the BankAccount class to make an instance of that class. The default way to do that for a generic class is simply className(), like in the above example with BankAccount(). This initializes your BankAccount object with default values.

Now, suppose you want to have some action happen with your BankAccount object, such as withdrawing or depositing money. The syntax for this looks like:

someBankAccount.deposit(1000.0)  // deposit $1000
someBankAccount.withdraw(300.0)  // withdraw $300

Swift subscribes to dot-syntax like most other languages, so this should be fairly unexciting to you. What you may be interested in is how a class is defined. Here would be the syntax for our BankAccount class:

class BankAccount {
  
  // default values for class attributes
  var accountHolderName: String
  var accountBalance: Float
  var accountPIN: UInt
  
  // initializes the BankAccount instance with passed values
  init(name _name: String, initialBalance _bal: Float, PIN _PIN: UInt) {
    self.accountHolderName = _name
    self.accountBalance = _bal
    self.accountPIN = _PIN % 10000  // keep it to 4 digits.
  }
  
  // default constructor
  init() {
    self.accountHolderName = "Bob Loblaw"
    self.accountBalance = -1.0
    self.accountPIN = 1111
  }
  
  // adds money to your account
  func deposit(amount: Float) {
    self.accountBalance += amount
  }
  
  // subtracts money from your account
  func withdraw(amount: Float) {
    self.accountBalance -= amount
  }
}

Okay, that definitely seems like a lot of stuff being thrown at you. But you should be able to figure it out. The class is named BankAccount (obv), and it has three attributes, one for name, balance, and PIN. It has two init functions, one which takes in three arguments, and another which takes in no arguments. And then it has two very simple mutator functions. This stuff is not terribly exciting or confusing.

var someBankAccount: BankAccount = BankAccount()  // defined by default constructor
var otherBankAccount: BankAccount = BankAccount(
    name: "Mike", initialBalance: 10000, PIN: 1234)
otherBankAccount.withdraw(1000)
println(String(otherBankAccount.accountBalance))

What will be printed?

One more thing: external parameter names with constructors are a little bit different. With constructors, all parameters have implicit hashtags before them. So, we could write the constructor like this:

// initializes the BankAccount instance with passed values
init(name: String, initialBalance: Float, PIN: UInt) {
    self.accountHolderName = name
    self.accountBalance = initialBalance
    self.accountPIN = PIN % 10000  // keep it to 4 digits.
} 

...

var account: BankAccount = BankAccount(name: "Mike", initialBalance: 0, PIN: 0000)