Swift

Nomenclature

variable
functionName

ClassName
StructName

Comments

// Single line comment

/*
  Multiline
  comment
*/

Comments can use Markdown. (Editor → Show Rendered Markup) Use semicolons :. Add images to Resources.

//: Markdown

/*:
  Multiline
  markdown

  ![Image](Logo.jpg)
*/
// MARK

Variables

let constant = "constant string"
var variable = "variable string"
variable = "changed string"

Variable definition

var text: String

Value types

  • String
  • Int
  • Bool
  • Double

Strings

let label = "The size is" + String(50) + "."
let label = "The width is \(50)"

Arrays

var colours = ["red", "green", "blue"]
colours[0]

colours.append("orange")
colours.remove(at: 1)

Optionals

var answer: String?
UILabel().text = answer

var answerString: String!
var food: Vegetable?
food = nil
food = Vegetable("carrot")

Optional binding

var answer: String?
if let sureAnswer = answer {
  UILabel().text = sureAnswer
}

// shorthand
UILabel().text = sureAnswer ?? ""

Unwrapping Optionals

Force-unwrapping

print(food!)
if let veggie = food {
  print(veggie)
} else {

}

Optional chaining

food?.mash()
food?.ingredient = "mustard"

Nil-coalescing operator

let freshVeggie = food ?? Vegetable("salad")

Ways to handle optionals

var emoji: String? = nil

if emoji != nil {
    // use emoji
}

if let emoji = emoji {
    // use emoji
}

func useEmoji(_ emoji: String?) {
  guard let emoji = emoji else {
    return
  }
  // use emoji
}

// Related: try - catch

func useEmoji2(_ emoji: String?) {
  do {
    let unwrappedEmoji = try unwrapEmoji(emoji)
  } catch {
    // no emoji
  }
}

enum EmojiError: Error {
  case emojiUnwrapError
}

func unwrapEmoji(_ emoji: String?) throws -> String {
  if let emoji = emoji {
    return emoji
  } else {
    throw EmojiError.emojiUnwrapError
  }
}



try? unwrapEmoji(emoji)

Control Flow

if

if percentage >= 50 {
  print("high percentage")
} else {
  print("low percentage")
}
if percentage >= 50 && percentage < 90 {
  // between 50 and 90
}

Ternary operator

print(percentage >= 50 ? "yes" : "no")

switch

switch percentage {
  case 0...50: print("low")
  case 51...80: print("medium")
  case 80...100: print("high")
  default: print("not a percentage")
}

Loops

for colour in colours {
  print(colour)
}
ForEach(array) { value in
  // ...
}

Ranges

0..<totalNumber
0...totalNumber
itemsList[0..<itemsCount]
for index in 0..<itemsCount {

}

Functions

func pointToRetina(point: Int) -> Int {
  return point * 2
}

let retinaPixels = pointToRetina(point: 320)
func name(parameters) -> returnType {
  functionBody
}
func createRecipe(forIngredients ingredients: [Ingredient]) -> Recipe {

}

Functions as parameters

createSomething(_ kind: Kind, creator: { ingredients -> Recipe in

}) 


{ ingredient in "Cook \(ingredient)." }
{ _ in "😀" }

{ parameter in parameter == "😀" }
{ $0 == "😀" }

last argument

createSomething(_ kind: Kind) { ingredients -> Recipe in

}

Struct

  • struct is a value-type, i.e. it is copied when passed around

Examples of structs

  • Array
  • ...
struct UserStruct {
  var name: String
  var age: Int
  var job: String
}

var user = UserStruct(name: "Mike", age: 35, job: "Designer")
user.name
struct Vegetable {
  var name: String
}
struct Update: Identifiable {
  var id = UUID()
  var text: String
  var age: Double
}

### Initializer
* free `init`
* custom `init`

```swift
struct Vegetable {
  var name: String

  init(name: String) {
    name = name
  }
}

Mutating functions in structs

struct Vehicle {
  mutating func drive() {

  }
}

Type Property

static var numberOfGroceries: Int
static func doSomething() {

}

Class

  • class is a reference-type, i.e. it is referenced when passed around
class UserClass {
  var name: String
  var age: Int
  var job: String

  init(name: String, age: Int, job: String) {
    self.name = name
    self.age = age
    self.job = job
  }
}
class Vegetable: Plants, EatablePlant {

}

Enum

value type (copied when passed around)

enum Vegetable {
  case kale
  case broccoli
  case bellPepper
  case tomato(isPassata: Bool)

  func mash() {

  }
  var calories: Int {  }
}

let tomatoSoup = Vegetable.tomato(isPassata: true)

var veggie = Vegetable.kale
switch veggie {
  case .kale: break
  case .broccoli: print("hooray")
  case .tomato(let isPassata): print(isPassata ? "mashed tomato" : "whole tomato")
  default: print("summer is here")
}

Generics

struct MemoryGame<CardContent> {
  
}

```swift
struct MemoryGame<CardContent> where CardContent: Equatable {

}

Protocols


Access Control

var numberOfGroceries: Int
private var numberOfGroceries: Int
private(set) var numberOfGroceries: Int

Debugging

print("hello")