Resources

This page will collect important notes and code snippets from lectures. Feel free to refer back to this page for syntax/conceptual help.

Swift

Variable Initialization

Variables in Swift can be initialized with either the let or var keyword. Variables initialized with let cannot be mutated.

The following code will throw an error.

let num = 1 num = 2

However, variables initialized with the var keyword can be mutated. Keep this difference in mind, and use let wherever you can; using var on variables that are never mutated can have a detrimental effect on performance.

Swift is a statically-typed language (like Java). This means that variable types generally have to be explicitly declared. Swift also has a type-inference feature, which explains why the code snippet above does not require us to declare a type. When we provide a variable with a value, Swift can infer the type of that value. However, when we decline to provide a value to a variable at initialization, we must provide a type. For example:

var num: Int

Optionals

You can use optionals in situations when a value might be absent. An optional represents two possibilities: either there is a value (and you can unwrap the optional to access it), or there isn’t a value.

Say we’re creating a sign-up form for a social-media application. Some fields may not be mandatory for the successful creation of an account (middle name, website, etc.). We can use optionals to model this behavior in Swift:

var middleName: String? var website: String?

If you define an optional variable without providing a value (like the situation above), then the variable is automatically set to nil for you.

Now, let’s imagine that a user has filled out our sign-up form. If the user has filled out the middleName or website field, we’ve bound their input to the variables above. To display this information on their profile, we have to unwrap both the middleName and website variables. There are a number of different ways to unwrap optional variables.

Unwrapping Optionals

Force Unwrapping

You can access an optional’s underlying value by adding an exclamation point (!) to the end of the optional’s name. If the optional does not have a value associated with it, your application will crash.

print(middleName!) print(website!)

Do not force-unwrap optionals.
Any oversight will cause your application to crash without warning.

Optional Binding (if-let)

You can use optional binding to check if an optional value, and if so, make that value available as a temporary variable.

if let mN = middleName { print(mN) }

In the block of code above, if middleName is non-nil, its value is assigned to mN, and subsequently printed. Crucially, if middleName is nil, the code inside the if statement does not get executed.

mN is a temporary variable, its scope is only inside the if statement.

guard

You can use a guard statement if you want the value of an optional to be available outside the scope of an if statement, and you wish to terminate execution if the optional is nil.

guard let mN = middleName else { /* You must return in the else clause of a guard statement */ return } print(mN)

In this case, mN is available outside the scope of the guard clause, but we are forbidden from continuing execution if middleName is nil.

Functions

Functions can be defined in Swift in the manner indicated below:

func hello(input userInput: String) -> String { return "Hello, \(userInput)" }

In Swift, input is known as an argument label, and userInput is known as a parameter label. The argument label is used when the function is called (see the code below), and the parameter label is used inside the scope of the function to refer to the parameter.

hello(input: "World!")

The function signature below is also valid:

func hello(input: String) -> String { return "Hello, \(input)" }

In this case, both the parameter label and argument label are input.

Finally, if you want to be able to call your function without an argument label, you can place an _ in the signature:

func hello(_ input: String) -> String { return "Hello, \(input)" } hello("World!")

Enumerations

An enumeration allows you to group a set of related values, and work with those values in a type-safe fashion. For example, let’s assume we want to model a dice roll, and perform an action based on the result.

enum Dice { case one case two case three case four case five case six }

The values defined in the Dice enumeration (such as one, two, etc.) are called enumeration cases. You can use the case keyword to introduce new cases.

Now that we have the basic behavior of a die, we can use a switch statement to match enumeration cases.

func diceRollToAction(roll: Dice) { /* roll refers to the number our user has rolled */ switch roll { case .one: print("one") case .two: print("two") case .three: print("three") default: print("four or more") } }

Structures

Swift structures are a flexible construct (similar to classes). Structures can be created in an identical fashion to classes, with the struct keyword:

struct TestStruct { // Properties, initializers, etc. }

However, structures are pass-by-reference in Swift while classes are pass-by-value. This means that when structures are passed to functions or assigned to variables, the entirety of their contents are copied over. In contrast, classes only pass a reference to the functions or variables they are assigned to.

Basic UIKit Elements

UIView

AUIView is a blank view inside which other UI elements can be placed. You can use UIViews to invisibly group together elements; or to create custom reusable UI elements.

Initialization

lazy var customView: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false view.backgroundColor = .black return view }()

UILabel

A UILabel is a block of static text. The text displayed by a UILabel cannot be edited by the end-user, but can be dynamically changed in your app’s code.

Initialization

lazy var label: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.text = "Hello, world!" label.textColor = .black label.font = UIFont.boldSystemFont(ofSize: 12) return label }

numberOfLines

The numberOfLines propery of a UILabel refers to the maximum number lines the system can use to fit the label’s text into its bounding rectangle. By default, this property will be set to 1. If you want your label to span multiple lines (as allowed by the space allocated), set this property to 0

label.numberOfLines = 0

UITextField

A UITextField displays an area to gather single-line textual input from the user. Do not use this element if you’re expecting multi-line text input!

Initialization

lazy var textField: UITexField = { let textField = UITextField() textField.translatesAutoresizingMaskIntoConstraints = false // Set a placeholder to display when the field is empty textField.attributedPlaceholder = NSAttributedString(string: "Placeholder") return textField }()

Delegation

To respond to changes in a UITextField, take the following steps:

  1. Conform your ViewController to UITextFieldDelegate
  2. Set textField.delegate = self inside the viewDidLoad of your ViewController
  3. Implement the relevant method listed here
Example
class ViewController: UIViewController { lazy var textField: UITextField = { let textField = UITextField() textField.translatesAutoresizingMaskIntoConstraints = false // Set a placeholder to display when the field is empty textField.attributedPlaceholder = NSAttributedString(string: "Placeholder") return textField }() override func viewDidLoad() { textField.delegate = self } } extension ViewController: UITextFieldDelegate { func textFieldDidBeginEditing(UITextField) { print("Text field did begin editing") } }

The code above will print Text field did begin editing whenever the user taps into the text field, and begins to type. The function textFieldDidBeginEditing is called by the system.

UITextView

A UITextView displays an area of multi-line text. This element can be used to present large bodies of editable, attributed text.

Initialization

lazy var textView: UITextView = { let textView = UITextView() textView.translatesAutoresizingMaskIntoConstraints = false textView.attributedText = NSAttributedString(string: "Hello,\n\nworld!") return textView }()

Delegation

See UITextField for delegation steps, here are the available methods.

UIImageView

A UIImageView displays an image within its bounds.

Initialization

Remember to place your image within the Assets.xcassets folder before attempting to display it!

lazy var imageView: UIImageView = { let imageView = UIImageView() imageView.translatesAutoresizingMaskIntoConstraints = false let image = UIImage(named: "test-image") imageView.image = image return imageView }()

UIStackView

A UIStackView arranges a collection of views in either a column or a row. Stack views can handle large amounts of UI complexity without constraints, and are often an excellent tool for interface creation.

Important Properties and Methods

Initialization

lazy var stackView: UIStackView = { let stack = UIStackView() stack.axis = .horizontal stack.distribution = .fillEqually stack.spacing = 5 stack.addArrangedSubview(label) stack.addArrangedSubview(textField) }()