Swift Cheat Sheet

Use this Swift cheat sheet as a quick reference for syntax, variables, data types, strings, collections, functions, closures, optionals, structs, classes, protocols, enums, error handling, async code, and common Swift patterns.

Basic Swift Syntax

Swift code can run in Xcode, Swift Playgrounds, or a Swift project.

print("Hello, Swift")

Syntax Basics

  • Use let for constants.
  • Use var for values that can change.
  • Swift is type-safe.
  • Swift uses type inference when the type is clear.
  • Statements do not need semicolons.
  • Code blocks use curly braces.

Comments

Single-Line Comment

// This is a single-line comment

Multi-Line Comment

/*
This comment can span
multiple lines.
*/

Use comments to explain why code exists, especially when the reason is not obvious.

Constants and Variables

Constant with let

Use let when the value should not change.

let appName = "Mimo"
let maxAttempts = 3

Variable with var

Use var when the value needs to change.

var score = 0
score += 10

print(score)

Type Annotation

Swift can infer types, but you can also write them explicitly.

let username: String = "Alex"
let age: Int = 28
let isActive: Bool = true

Use type annotations when they make code clearer or when Swift cannot infer the type.

Basic Data Types

String

let name: String = "Alex"

Int

let age: Int = 28

Double

let price: Double = 19.99

Float

let progress: Float = 0.75

Bool

let isLoggedIn: Bool = true

Character

let grade: Character = "A"

Type Inference

Swift often detects the type from the value.

let name = "Alex"
let age = 28
let price = 19.99
let isActive = true

Swift understands:

  • name is a String.
  • age is an Int.
  • price is a Double.
  • isActive is a Bool.

Add a type when you need a specific one.

let progress: Float = 0.75

Strings

Create a String

let greeting = "Hello"

String Interpolation

Use \() to insert values into a string.

let name = "Alex"
let message = "Hello, \(name)"

print(message)

Multiline String

let text = """
Line one
Line two
Line three
"""

String Length

let language = "Swift"

print(language.count)

Change Case

let text = "Swift"

print(text.lowercased())
print(text.uppercased())

Check Text

let title = "Learn Swift"

print(title.contains("Swift"))
print(title.hasPrefix("Learn"))
print(title.hasSuffix("Swift"))

Split a String

let tags = "swift,ios,xcode"
let tagList = tags.split(separator: ",")

print(tagList)

Join Strings

let words = ["Learn", "Swift"]
let sentence = words.joined(separator: " ")

print(sentence)

Numbers and Math

Basic Math

let a = 10
let b = 3

print(a + b)
print(a - b)
print(a * b)
print(a / b)

Integer division removes the decimal part.

print(10 / 3)

For decimal results, use Double.

let result = 10.0 / 3.0

print(result)

Remainder

let remainder = 10 % 3

print(remainder)

Convert Number Types

let count = 5
let price = 19.99

let total = Double(count) * price

print(total)

Swift does not automatically mix numeric types. Convert them when needed.

Operators

Assignment

var score = 10

score += 5
score -= 2
score *= 3
score /= 2

Comparison

print(10 == 10)
print(10 != 5)
print(10 > 5)
print(10 >= 10)
print(5 < 10)
print(5 <= 5)

Logical Operators

let isAdult = true
let hasTicket = false

print(isAdult && hasTicket)
print(isAdult || hasTicket)
print(!isAdult)

Range Operators

Closed range includes the end value.

for number in 1...5 {
    print(number)
}

Half-open range excludes the end value.

for number in 1..<5 {
    print(number)
}

Conditionals

if

let age = 20

if age >= 18 {
    print("Adult")
}

if...else

let isLoggedIn = false

if isLoggedIn {
    print("Welcome back")
} else {
    print("Please log in")
}

else if

let score = 85

if score >= 90 {
    print("A")
} else if score >= 80 {
    print("B")
} else {
    print("Keep practicing")
}

Switch Statements

Use switch to compare a value against multiple cases.

let role = "admin"

switch role {
case "admin":
    print("Full access")
case "editor":
    print("Edit access")
default:
    print("Read access")
}

Switch with Ranges

let score = 82

switch score {
case 90...100:
    print("A")
case 80..<90:
    print("B")
case 70..<80:
    print("C")
default:
    print("Keep practicing")
}

Swift switch statements must cover all possible values. Use default when needed.

Loops

for...in

let languages = ["Swift", "JavaScript", "Python"]

for language in languages {
    print(language)
}

Loop Through a Range

for number in 1...5 {
    print(number)
}

while

var count = 0

while count < 3 {
    print(count)
    count += 1
}

repeat...while

Runs at least once.

var count = 0

repeat {
    print(count)
    count += 1
} while count < 3

Loop with Index

let names = ["Alex", "Sam", "Taylor"]

for (index, name) in names.enumerated() {
    print("\(index): \(name)")
}

Break and Continue

for number in 1...10 {
    if number == 5 {
        break
    }

    print(number)
}
for number in 1...5 {
    if number == 3 {
        continue
    }

    print(number)
}

Arrays

Arrays store ordered values.

let fruits = ["apple", "banana", "orange"]

Array Type Annotation

let names: [String] = ["Alex", "Sam", "Taylor"]
let scores: [Int] = [90, 85, 100]

Create an Empty Array

var items: [String] = []

Access Items

let fruits = ["apple", "banana", "orange"]

print(fruits[0])
print(fruits[1])

Add Items

var fruits = ["apple", "banana"]

fruits.append("orange")
fruits += ["mango"]

print(fruits)

Change an Item

var fruits = ["apple", "banana"]

fruits[1] = "mango"

print(fruits)

Remove Items

var fruits = ["apple", "banana", "orange"]

fruits.remove(at: 1)
fruits.removeLast()

print(fruits)

Array Count

let fruits = ["apple", "banana", "orange"]

print(fruits.count)

Check If Empty

let items: [String] = []

if items.isEmpty {
    print("No items")
}

Array Methods

Map

let numbers = [1, 2, 3]

let doubled = numbers.map { number in
    number * 2
}

print(doubled)

Short version:

let doubled = numbers.map { $0 * 2 }

Filter

let numbers = [1, 2, 3, 4, 5]

let evenNumbers = numbers.filter { number in
    number % 2 == 0
}

print(evenNumbers)

Reduce

let prices = [10, 20, 30]

let total = prices.reduce(0) { sum, price in
    sum + price
}

print(total)

Short version:

let total = prices.reduce(0, +)

Sort

var numbers = [3, 1, 4, 2]

numbers.sort()

print(numbers)

Create a sorted copy:

let numbers = [3, 1, 4, 2]
let sortedNumbers = numbers.sorted()

print(sortedNumbers)

Dictionaries

Dictionaries store key-value pairs.

let user = [
    "name": "Alex",
    "role": "Developer"
]

Dictionary Type Annotation

var scores: [String: Int] = [
    "Alex": 90,
    "Sam": 85
]

Create an Empty Dictionary

var users: [String: String] = [:]

Access a Value

Dictionary access returns an optional.

let scores = [
    "Alex": 90,
    "Sam": 85
]

let alexScore = scores["Alex"]

print(alexScore)

Add or Update a Value

var scores = [
    "Alex": 90
]

scores["Sam"] = 85
scores["Alex"] = 95

print(scores)

Remove a Value

var scores = [
    "Alex": 90,
    "Sam": 85
]

scores.removeValue(forKey: "Sam")

print(scores)

Loop Through a Dictionary

let scores = [
    "Alex": 90,
    "Sam": 85
]

for (name, score) in scores {
    print("\(name): \(score)")
}

Sets

Sets store unique unordered values.

var tags: Set<String> = ["swift", "ios", "swift"]

print(tags)

Add and Remove

var tags: Set<String> = ["swift", "ios"]

tags.insert("xcode")
tags.remove("ios")

print(tags)

Check Membership

let tags: Set<String> = ["swift", "ios"]

print(tags.contains("swift"))

Set Operations

let a: Set = ["swift", "ios", "xcode"]
let b: Set = ["swift", "macos"]

print(a.union(b))
print(a.intersection(b))
print(a.subtracting(b))

Use sets when uniqueness matters more than order.

Functions

Define a Function

func greet(name: String) -> String {
    return "Hello, \(name)"
}

print(greet(name: "Alex"))

Function with No Return Value

func logMessage(_ message: String) {
    print(message)
}

logMessage("Task complete")

External and Internal Parameter Names

func greet(person name: String) {
    print("Hello, \(name)")
}

greet(person: "Alex")

person is the external name. name is used inside the function.

Omit External Parameter Name

func square(_ number: Int) -> Int {
    return number * number
}

print(square(5))

Default Parameter Value

func greet(name: String = "Guest") {
    print("Hello, \(name)")
}

greet()
greet(name: "Alex")

Return Multiple Values

Use a tuple to return more than one value.

func getUser() -> (name: String, age: Int) {
    return ("Alex", 28)
}

let user = getUser()

print(user.name)
print(user.age)

You can also destructure the tuple.

let (name, age) = getUser()

print(name)
print(age)

Closures

Closures are reusable blocks of code.

let greet = { (name: String) -> String in
    return "Hello, \(name)"
}

print(greet("Alex"))

Closure as a Function Argument

let numbers = [1, 2, 3]

let doubled = numbers.map { number in
    number * 2
}

print(doubled)

Shorthand Closure Arguments

let numbers = [1, 2, 3]

let doubled = numbers.map { $0 * 2 }

print(doubled)

Use shorthand when the closure stays easy to read.

Optionals

An optional can hold a value or nil.

var username: String? = "Alex"
username = nil

Use optionals when a value may be missing.

Optional Type

let email: String? = nil

String? means the value is either a String or nil.

Optional Binding

Use if let to unwrap an optional safely.

let email: String? = "alex@example.com"

if let email = email {
    print(email)
} else {
    print("No email")
}

guard let

Use guard let when you want to exit early if a value is missing.

func sendEmail(to email: String?) {
    guard let email = email else {
        print("Missing email")
        return
    }

    print("Sending email to \(email)")
}

guard keeps the successful path less nested.

Nil Coalescing

Use ?? to provide a fallback value.

let username: String? = nil
let displayName = username ?? "Guest"

print(displayName)

This uses "Guest" only when username is nil.

Optional Chaining

Use optional chaining to access properties or methods on optional values.

struct Profile {
    let email: String
}

struct User {
    let profile: Profile?
}

let user = User(profile: nil)

print(user.profile?.email)

If profile is nil, the result is nil instead of a crash.

Force Unwrapping

Force unwrapping uses !.

let email: String? = "alex@example.com"

print(email!)

Only force unwrap when you are certain the optional has a value. If it is nil, the app crashes.

Safer:

if let email = email {
    print(email)
}

Structs

Structs define custom value types.

struct User {
    let name: String
    var age: Int
}

let user = User(name: "Alex", age: 28)

print(user.name)

Add a Method

struct User {
    let name: String

    func greet() -> String {
        return "Hello, \(name)"
    }
}

let user = User(name: "Alex")

print(user.greet())

Mutating Method

Use mutating when a struct method changes its own properties.

struct Counter {
    var count = 0

    mutating func increase() {
        count += 1
    }
}

var counter = Counter()
counter.increase()

print(counter.count)

Classes

Classes define reference types.

class User {
    let name: String

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

    func greet() -> String {
        return "Hello, \(name)"
    }
}

let user = User(name: "Alex")

print(user.greet())

Class Inheritance

class Animal {
    func speak() {
        print("Sound")
    }
}

class Dog: Animal {
    override func speak() {
        print("Bark")
    }
}

let dog = Dog()
dog.speak()

Use override when a subclass changes a superclass method.

Structs vs Classes

Use Structs When:

  • You need value semantics.
  • You model simple data.
  • You do not need inheritance.
  • You want copies to be independent.

Use Classes When:

  • You need shared reference behavior.
  • You need inheritance.
  • You work with APIs that require classes.
  • You need identity checks.

Most Swift models start well as structs.

Enums

Enums define a fixed set of cases.

enum Direction {
    case up
    case down
    case left
    case right
}

let direction = Direction.up

Switch on an Enum

switch direction {
case .up:
    print("Move up")
case .down:
    print("Move down")
case .left:
    print("Move left")
case .right:
    print("Move right")
}

Enum with Raw Values

enum Status: String {
    case draft = "draft"
    case published = "published"
    case archived = "archived"
}

print(Status.published.rawValue)

Enum with Associated Values

enum ResultState {
    case loading
    case success(data: String)
    case failure(message: String)
}

let state = ResultState.success(data: "Loaded")

switch state {
case .loading:
    print("Loading")
case .success(let data):
    print(data)
case .failure(let message):
    print(message)
}

Associated values are useful for states that carry extra data.

Protocols

Protocols define requirements that a type must follow.

protocol Greetable {
    var name: String { get }

    func greet() -> String
}

Conform to a protocol:

struct User: Greetable {
    let name: String

    func greet() -> String {
        return "Hello, \(name)"
    }
}

Use protocols to describe shared behavior across different types.

Extensions

Extensions add functionality to an existing type.

extension String {
    func shout() -> String {
        return self.uppercased()
    }
}

let message = "hello"

print(message.shout())

Extend a Custom Type

struct User {
    let name: String
}

extension User {
    func greet() -> String {
        return "Hello, \(name)"
    }
}

Extensions help organize code without changing the original type definition.

Computed Properties

Computed properties calculate a value.

struct Rectangle {
    let width: Double
    let height: Double

    var area: Double {
        width * height
    }
}

let rectangle = Rectangle(width: 10, height: 5)

print(rectangle.area)

Use computed properties when a value can be derived from other properties.

Property Observers

Property observers run when a property changes.

var score = 0 {
    willSet {
        print("Score will change to \(newValue)")
    }

    didSet {
        print("Score changed from \(oldValue) to \(score)")
    }
}

score = 10

Use observers for side effects tied to property changes.

Access Control

Access control limits where code can be used.

Common Access Levels

  • open allows subclassing and access outside the module.
  • public allows access outside the module.
  • internal allows access inside the module and is the default.
  • fileprivate allows access inside the same file.
  • private allows access inside the enclosing scope.

Private Property

struct Account {
    private var balance: Double = 0

    mutating func deposit(_ amount: Double) {
        balance += amount
    }
}

Use private to protect implementation details.

Error Handling

Define an error type with an enum.

enum LoginError: Error {
    case missingEmail
    case invalidPassword
}

Throw an error:

func login(email: String, password: String) throws {
    if email.isEmpty {
        throw LoginError.missingEmail
    }

    if password.count < 8 {
        throw LoginError.invalidPassword
    }

    print("Logged in")
}

Handle errors with do, try, and catch.

do {
    try login(email: "", password: "123")
} catch LoginError.missingEmail {
    print("Email is required")
} catch LoginError.invalidPassword {
    print("Password is too short")
} catch {
    print("Something went wrong")
}

try? and try!

Use try? to convert a thrown result into an optional.

let result = try? login(email: "alex@example.com", password: "password123")

Use try! only when you are certain the function will not throw.

try! login(email: "alex@example.com", password: "password123")

If the function throws, try! crashes the app.

Generics

Generics let code work with different types.

func printValue<T>(_ value: T) {
    print(value)
}

printValue("Hello")
printValue(42)

Generic Function That Returns a Value

func firstItem<T>(from items: [T]) -> T? {
    return items.first
}

let firstName = firstItem(from: ["Alex", "Sam"])
let firstNumber = firstItem(from: [1, 2, 3])

Generic Type Constraint

func printCount<T: Collection>(_ items: T) {
    print(items.count)
}

printCount(["Swift", "iOS"])

Use constraints when the generic type must support specific behavior.

Async and Await

Use async and await for asynchronous code.

func fetchUsername() async -> String {
    return "Alex"
}

Call it with await from another async context.

let username = await fetchUsername()

print(username)

Async Throwing Function

enum NetworkError: Error {
    case failed
}

func fetchData() async throws -> String {
    throw NetworkError.failed
}

Handle it with do, try, and await.

do {
    let data = try await fetchData()
    print(data)
} catch {
    print("Request failed")
}

Tasks

Use Task to start async work from synchronous code.

Task {
    let username = await fetchUsername()
    print(username)
}

This is common in SwiftUI views and app code that needs to call async functions.

Main Actor

Use @MainActor for code that updates UI state.

@MainActor
func updateUI() {
    print("Update UI on the main actor")
}

In SwiftUI, UI-related state often updates on the main actor.

SwiftUI Basics

SwiftUI uses structs to define views.

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, SwiftUI")
    }
}

VStack

VStack {
    Text("Title")
    Text("Subtitle")
}

HStack

HStack {
    Text("Left")
    Text("Right")
}

Button

Button("Tap me") {
    print("Tapped")
}

State

import SwiftUI

struct CounterView: View {
    @State private var count = 0

    var body: some View {
        Button("Count: \(count)") {
            count += 1
        }
    }
}

Use @State for local view state.

Common Swift Patterns

Safe Optional Handling

func displayName(_ name: String?) -> String {
    guard let name = name else {
        return "Guest"
    }

    return name
}

Filter an Array

let users = [
    "Alex",
    "Sam",
    "Taylor"
]

let filteredUsers = users.filter { user in
    user.hasPrefix("A")
}

print(filteredUsers)

Find an Item

let numbers = [1, 2, 3, 4]

let firstEven = numbers.first { number in
    number % 2 == 0
}

print(firstEven)

Group State with an Enum

enum ViewState {
    case loading
    case loaded(items: [String])
    case failed(message: String)
}

let state = ViewState.loaded(items: ["Swift", "iOS"])

Format a Simple Model

struct Course {
    let title: String
    let lessonCount: Int

    var summary: String {
        "\(title): \(lessonCount) lessons"
    }
}

let course = Course(title: "Swift Basics", lessonCount: 12)

print(course.summary)

Common Mistakes

Using var When let Is Enough

var name = "Alex"

Better:

let name = "Alex"

Use let by default. Switch to var only when the value needs to change.

Force Unwrapping Too Early

let email: String? = nil

print(email!)

Better:

if let email = email {
    print(email)
} else {
    print("No email")
}

Force unwrapping a nil value crashes the app.

Changing a let Constant

let score = 10
score = 20

Better:

var score = 10
score = 20

Use var only when reassignment is required.

Forgetting mutating in a Struct

struct Counter {
    var count = 0

    func increase() {
        count += 1
    }
}

Better:

struct Counter {
    var count = 0

    mutating func increase() {
        count += 1
    }
}

Struct methods need mutating when they change stored properties.

Mixing Numeric Types

let count = 3
let price = 19.99

let total = count * price

Better:

let count = 3
let price = 19.99

let total = Double(count) * price

Swift does not automatically multiply Int and Double.

Debugging Tips

Print Values

print(user)

Print Labels

print("Current user:", user)

Check Optional Values

let email: String? = nil

print(email as Any)

Casting to Any can silence optional print warnings when you are debugging.

Use Breakpoints in Xcode

Set a breakpoint by clicking the line number area in Xcode. Run the app, then inspect variables when execution pauses.

Read Error Messages Carefully

Swift errors often tell you:

  • Which type Swift expected
  • Which type you provided
  • Which value may be optional
  • Which function needs try
  • Which async call needs await

Quick Reference

Print Output

print("Hello")

Create a Constant

let name = "Alex"

Create a Variable

var count = 0

Create an Array

let items = ["one", "two", "three"]

Create a Dictionary

let user = [
    "name": "Alex",
    "role": "Developer"
]

Create a Function

func greet(name: String) -> String {
    return "Hello, \(name)"
}

Create an Optional

let email: String? = nil

Unwrap an Optional

if let email = email {
    print(email)
}

Use a Guard Statement

guard let email = email else {
    return
}

Create a Struct

struct User {
    let name: String
}

Create a Class

class User {
    let name: String

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

Create an Enum

enum Status {
    case loading
    case success
    case failure
}

Create a Protocol

protocol Greetable {
    func greet() -> String
}

Handle Errors

do {
    try riskyFunction()
} catch {
    print(error)
}

Use Async Code

Task {
    let result = await loadData()
    print(result)
}