Swift
March 25, 2022

## Decimals

• When you create a floating-point number, Swift considers it to be a `Double`. That’s short for “double-precision floating-point number”.
• Swift considers decimals to be a wholly different type of data to integers, which means you can’t mix them together. After all, integers are always 100% accurate, whereas decimals are not, so Swift won’t let you put the two of them together unless you specifically ask for it to happen.
• Swift decides whether you wanted to create a `Double` or an `Int` based on the number you provide

Older APIs use `CGFloat`. If you see `CGFloat` you can just ignore it and use `Double`.

## Collection Types

Swift provides three primary collection types, known as `arrays`, `sets`, and `dictionaries`, for storing collections of values. Arrays are ordered collections of values. Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations.

### Arrays

An array stores values of the same type in an ordered list. The same value can appear in an array multiple times at different positions.

### Sets

A set stores distinct values of the same type in a collection with no defined ordering. You can use a set instead of an array when the order of items isn’t important, or when you need to ensure that an item only appears once.

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 `````` ``````var letters = Set() print("letters is of type Set with \(letters.count) items.") // Prints "letters is of type Set with 0 items." var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"] // favoriteGenres has been initialized with three initial items for genre in favoriteGenres { print("\(genre)") } // Classical // Jazz // Hip hop``````

### Dictionaries

Dictionary is very similar to Java Map. It cannot contain duplicate keys: Each key can map to at most one value.

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 `````` ``````let person = [ "name": "John Doe", "title": "Mr", "location": "US" ] let hasGraduated = [ "Eric": false, "Maeve": true, "Otis": false, ] let olympics = [ 2012: "London", 2016: "Rio de Janeiro", 2021: "Tokyo" ]``````

You can also create an empty dictionary using whatever explicit types you want to store, then set keys one by one:

 ``````1 2 3 4 `````` ``````var heights = [String: Int]() heights["Yao Ming"] = 229 heights["Shaquille O'Neal"] = 216 heights["LeBron James"] = 206``````

## Type annotations

Type annotations let us be explicit about what data types we want.

 `````` 1 2 3 4 5 6 7 8 9 10 `````` ``````let surname: String = "Lasso" // Sttring var score: Int = 0 // Int let pi: Double = 3.141 // Double var isAuthenticated: Bool = true // Bool var albums: [String] = ["Red", "Fearless"] // Array var user: [String: String] = ["id": "@twostraws"] // Dictionary var books: Set = Set(["The Bluest Eye", "Foundation", "Girl, Woman, Other"]) // Set var teams: [String] = [String]() // Empty array of strings var cities: [String] = [] // Empty array of strings var clues = [String]() // Empty array of strings``````

## Conditions & Loops

### Loops

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 `````` ``````// Loop an array of strings let platforms = ["iOS", "macOS", "tvOS", "watchOS"] for os in platforms { print("Swift works great on \(os).") } // Loop between [1,12] for i in 1...12 { print("5 x \(i) is \(5 * i)") } // Loop between [1,5) for i in 1..<5 { print("Counting 1 up to 5: \(i)") } // Loop without loop variable var lyric = "Haters gonna" for _ in 1...5 { lyric += " hate" } // While loop var countdown = 5 while countdown > 0 { print("\(countdown)…") countdown -= 1 } // Repeat-While loop repeat { statements } while condition``````

If you call `continue` inside the loop body, Swift will immediately stop executing the current loop iteration and jump to the next item in the loop.

If you call `break` inside the loop body, Swift will exit the current loop immediately and skip all remaining iterations.

## Functions

### Return values

 ``````1 2 3 4 `````` ``````// Returns a single value as Bool func isUppercase(string: String) -> Bool { string == string.uppercased() }``````

In order to return multiple values from a function, an array, set or dictionary can be used as return type.

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 `````` ``````// Returns a single value as Array func getUser() -> [String] { ["Taylor", "Swift"] } // Returns a single value as Dictionary func getUser() -> [String: String] { [ "firstName": "Taylor", "lastName": "Swift" ] }``````

It is recommended to use `Tuple` to return multiple values. `Tuple` lets us put multiple pieces of data into a single variable. They have a fixed size and can have a variety of data types.

 `````` 1 2 3 4 5 6 7 8 9 10 11 `````` ``````func getUser() -> (firstName: String, lastName: String) { (firstName: "Taylor", lastName: "Swift") } let user = getUser() print("Name: \(user.firstName) \(user.lastName)") func getUser() -> (String, String) { ("Taylor", "Swift") } let user = getUser() print("Name: \(user.0) \(user.1)")``````

We can pull apart the return value from the function into two separate constants.

 ``````1 2 `````` ``````let (firstName, lastName) = getUser() print("Name: \(firstName) \(lastName)")``````

If you don’t need all the values from the tuple you can go a step further by using `_` to tell Swift to ignore that part of the tuple:

 ``````1 2 `````` ``````let (firstName, _) = getUser() print("Name: \(firstName)")``````

### Customizing parameter labels

Adding an underscore before the parameter name, it will remove the external parameter label.

 ``````1 2 3 4 5 6 `````` ``````func isUppercase(_ string: String) -> Bool { string == string.uppercased() } let string = "HELLO, WORLD" let result = isUppercase(string: string) // without underscore let result = isUppercase(string) // with underscore, it is no need to write an external parameter name``````

Another problem in parameters is `reserved keywords` that you cannot use the keywords as parameter name.

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 `````` ``````func printTimesTables(for: Int) { for i in 1...12 { print("\(i) x \(for) is \(i * for)") // throws error since `for` is not allowed inside the function } } printTimesTables(for: 5) func printTimesTables(for number: Int) { for i in 1...12 { print("\(i) x \(number) is \(i * number)") } } printTimesTables(for: 5) // So, now you can use `for` as second parameter name``````

## Closures

Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to lambdas in Java and other programming languages.

Closures can capture and store references to any constants and variables from the context in which they’re defined. This is known as `closing over` those constants and variables.

 ``````1 2 3 4 `````` ``````// Closure Expression Syntax { (parameters) -> return type in statements }``````
 ``````1 2 3 4 5 6 7 8 9 `````` ``````let team = ["Gloria", "Suzanne", "Piper", "Tiffany", "Tasha"] let captainFirstTeam = team.sorted(by: { (name1: String, name2: String) -> Bool in if name1 == "Suzanne" { return true } else if name2 == "Suzanne" { return false } return name1 < name2 })``````

Swift can automatically provide parameter names for us, using `shorthand syntax`. Swift provides for us: `\$0` and `\$1`, for the first and second string parameters respectively.

 ``````1 `````` ``let reverseTeam = team.sorted { \$0 > \$1 }``

### Functions as parameters

Having three trailing closures is not as uncommon as you might expect. To demonstrate this here’s a function that accepts three function parameters, each of which accept no parameters and return nothing:

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 `````` ``````func doImportantWork(first: () -> Void, second: () -> Void, third: () -> Void) { print("About to start first work") first() print("About to start second work") second() print("About to start third work") third() print("Done!") } doImportantWork { print("This is the first work") } second: { print("This is the second work") } third: { print("This is the third work") }``````

## Structures and Classes

Swift doesn’t require you to create separate interface and implementation files for custom structures and classes.

Structures and classes in Swift have many things in common. Both can:

• Define properties to store values
• Define methods to provide functionality
• Define subscripts to provide access to their values using subscript syntax
• Define initializers to set up their initial state
• Be extended to expand their functionality beyond a default implementation
• Conform to protocols to provide standard functionality of a certain kind

Classes have additional capabilities that structures don’t have:

• Inheritance enables one class to inherit the characteristics of another.
• Type casting enables you to check and interpret the type of a class instance at runtime.
• Deinitializers enable an instance of a class to free up any resources it has assigned.
• Reference counting allows more than one reference to a class instance.

### Dynamic property values

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 `````` ``````struct Employee { let name: String var vacationAllocated = 14 var vacationTaken = 0 // only getter var vacationRemaining: Int { vacationAllocated - vacationTaken } // with getter and setter var vacationRemaining: Int { get { vacationAllocated - vacationTaken } set { vacationAllocated = vacationTaken + newValue } } }``````

### Take action when a property changes

In Swift, there are `property observers` that run when properties change. A `didSet` observer to run when the property just changed, and a `willSet` observer to run before the property changed.

 ``````1 2 3 4 5 6 7 `````` ``````struct Game { var score = 0 { didSet { print("Score is now \(score)") } } }``````

Swift automatically provides the constant `oldValue` inside `didSet` and the constant `newValue` inside `willSet`.

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 `````` ``````struct App { var contacts = [String]() { willSet { print("Current value is: \(contacts)") print("New value will be: \(newValue)") } didSet { print("There are now \(contacts.count) contacts.") print("Old value was \(oldValue)") } } } var app = App() app.contacts.append("Adrian E") app.contacts.append("Allen W") app.contacts.append("Ish S")``````

### Initializers

Swift silently generates the initializer for us based on the properties we place inside a struct. You can still create a custom one yourself.

Swift won’t automatically generate a memberwise initializer for classes. This means you either need to write your own initializer, or assign default values to all your properties.

### Inheritance

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 `````` ``````class Employee { let hours: Int init(hours: Int) { self.hours = hours } func printSummary() { print("I work \(hours) hours a day.") } } class Developer: Employee { let isPrincipal: Bool init(hours: Int, isPrincipal: Bool) { self.isPrincipal = isPrincipal super.init(hours: hours) } func work() { print("I'm writing code for \(hours) hours.") } override func printSummary() { print("I'm a developer who will sometimes work \(hours) a day, but other times spend hours arguing about whether code should be indented using tabs or spaces.") } } class Manager: Employee { func work() { print("I'm going to meetings for \(hours) hours.") } }``````

### Copy classes and structures

 ``````1 2 3 4 5 6 7 8 `````` ``````class User { var username = "Anonymous" } var user1 = User() var user2 = user1 user2.username = "Taylor" print(user1.username) // Taylor print(user2.username) // Taylor``````

Structs do not share their data amongst copies, meaning that if we change `class User` to `struct User` in our code we get a different result.

 ``````1 2 3 4 5 6 7 8 `````` ``````struct User { var username = "Anonymous" } var user1 = User() var user2 = user1 user2.username = "Taylor" print(user1.username) // Anonymous print(user2.username) // Taylor``````

If you want to create a unique copy of a class instance – sometimes called a deep copy – you need to handle creating a new instance and copy across all your data safely.

 ``````1 2 3 4 5 6 7 8 9 `````` ``````class User { var username = "Anonymous" func copy() -> User { let user = User() user.username = username return user } }``````

## Extensions

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. An extension can extend an existing type to make it adopt one or more protocols.

 ``````1 2 3 `````` ``````extension SomeType: SomeProtocol, AnotherProtocol { // implementation of protocol requirements goes here }``````

Example: You can extend the Rect structure to provide an additional initializer that takes a specific center point and size:

 ``````1 2 3 4 5 6 7 `````` ``````extension Rect { init(center: Point, size: Size) { let originX = center.x - (size.width / 2) let originY = center.y - (size.height / 2) self.init(origin: Point(x: originX, y: originY), size: size) } }``````

## Protocols

Swift protocols are very similar to Java interfaces.

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 `````` ``````protocol SomeProtocol { init(someParameter: Int) // Initializer Requirements var mustBeSettable: Int { get set } // Property Requirements var doesNotNeedToBeSettable: Int { get } // Property Requirements static func someTypeMethod() // Method Requirements } protocol AnotherProtocol { static var someTypeProperty: Int { get set } // Property Requirements func random() -> Double // Method Requirements mutating func toggle() // Mutating Method Requirements } struct SomeStructure: FirstProtocol, AnotherProtocol { // structure definition goes here } class SomeClass: SomeProtocol, FirstProtocol, AnotherProtocol { // The following is due to Initializer Requirements in `SomeProtocol` required init(someParameter: Int) { // initializer implementation goes here } // class definition goes here }``````

### Comparable

`Comparable` is a Swift protocol, which allows Swift to see if one object should be sorted before another. Custom types cannot be implemented automatically by Swift. It is needed to write a function called `<` that accepts two instances of your struct as its parameter, and returns true if the first instance should be sorted before the second.

 ``````1 2 3 4 5 6 7 `````` ``````struct Location: Equatable, Comparable { let name: String } func <(lhs: Location, rhs: Location) -> Bool { lhs.name < rhs.name }``````

## Optionals

### Unwrapping optionals

By using `variable shadowing`, we are temporarily creating a second constant of the same name, available only inside the condition’s body. It is very common and mainly used with optional unwraps.

with `if let`, it lets us run if number has a value inside.

 ``````1 2 3 4 5 `````` ``````var number: Int? = nil if let number = number { // Run if number has a value inside print(function1(number: number)) }``````

with `guard let`, it lets us run if number doesn’t have a value inside.

 ``````1 2 3 4 5 6 7 8 `````` ``````func printSquare(of number: Int?) { // Run if number doesn't have a value inside guard let number = number else { print("Missing input") return } print("\(number) x \(number) is \(number * number)") }``````

with `nil coalescing operator`, it lets us provide a default value if the optional was empty.

 ``````1 2 3 4 5 6 7 `````` ``````let captains = [ "Enterprise": "Picard", "Voyager": "Janeway", "Defiant": "Sisko" ] let new = captains["Serenity"] ?? "N/A" let new = captains["Serenity", default: "N/A"]``````

### Optional chaining

 ``````1 2 3 4 5 6 7 `````` ``````struct Book { let title: String let book: String? } var book: Book? = nil let author = book?.author?.first?.uppercased() ?? "A"``````