NexusCS

Swift

Programming
Quick reference for Swift - Apple's modern, safe, and fast programming language for iOS, macOS, watchOS, tvOS, and server-side development.
featured

Getting started

Hello World

print("Hello, World!")

Variables & Constants

var variable = 42              // Mutable
let constant = 42              // Immutable (preferred)
var explicit: Int = 42         // Explicit type

Type Inference

let inferredInt = 42           // Int
let inferredDouble = 3.14      // Double
let inferredString = "Hello"   // String
let inferredBool = true        // Bool

String Interpolation

let name = "World"
print("Hello, \(name)!")       // Hello, World!

let x = 3, y = 5
print("\(x) × \(y) = \(x * y)") // 3 × 5 = 15

Basic Types

Numbers

let integer: Int = 42
let float: Float = 3.14
let double: Double = 3.14159
let hex: Int = 0xFF            // 255
let binary: Int = 0b1010       // 10
let octal: Int = 0o21          // 17

Strings

let str = "Hello"
let multi = """
  Multiple
  lines
  """
str.isEmpty                    // false
str.count                      // 5
str.uppercased()               // "HELLO"
str.lowercased()               // "hello"

String Operations

let hello = "Hello"
let world = "World"
hello + " " + world            // "Hello World"
hello.contains("ell")          // true
hello.hasPrefix("He")          // true
hello.hasSuffix("lo")          // true

Booleans

let isTrue = true
let isFalse = false
!isTrue                        // false
isTrue && isFalse              // false
isTrue || isFalse              // true

Optionals

Declaration

var optionalInt: Int? = nil
optionalInt = 42

var implicitOptional: Int! = 42 // ⚠️ Implicitly unwrapped

Safe Unwrapping

// Optional binding
if let value = optionalInt {
    print(value)               // Safe access
}

// Guard statement
guard let value = optionalInt else {
    return
}
print(value)                   // Available in scope

// Nil coalescing
let result = optionalInt ?? 0  // Use 0 if nil

Optional Chaining

class Person {
    var name: String?
}

let person: Person? = Person()
let upperName = person?.name?.uppercased()
// Returns String? (nil if any step is nil)

Force Unwrapping

let value = optionalInt!       // ⚠️ Crashes if nil

Collections

Arrays

var numbers = [1, 2, 3]
var empty: [Int] = []
var explicit = Array<Int>()

numbers.append(4)              // [1, 2, 3, 4]
numbers.insert(0, at: 0)       // [0, 1, 2, 3, 4]
numbers.remove(at: 0)          // [1, 2, 3, 4]
numbers[0]                     // 1
numbers.count                  // 4
numbers.isEmpty                // false
numbers.first                  // Optional(1)
numbers.last                   // Optional(4)

Dictionaries

var dict = ["key": "value"]
var empty: [String: Int] = [:]

dict["newKey"] = "newValue"
dict["key"]                    // Optional("value")
dict["missing"]                // nil
dict.removeValue(forKey: "key")
dict.count                     // Count of pairs
dict.keys                      // Keys collection
dict.values                    // Values collection

Sets

var set: Set = [1, 2, 3]
var empty = Set<Int>()

set.insert(4)
set.remove(1)
set.contains(2)                // true
set.count                      // 3

// Set operations
let a: Set = [1, 2, 3]
let b: Set = [3, 4, 5]
a.union(b)                     // {1, 2, 3, 4, 5}
a.intersection(b)              // {3}
a.subtracting(b)               // {1, 2}

Tuples

let tuple = (1, "two", 3.0)
tuple.0                        // 1
tuple.1                        // "two"

let named = (x: 1, y: 2)
named.x                        // 1

let (a, b) = (1, 2)           // Decomposition
let (x, _) = (1, 2)           // Ignore with _

Control Flow

If Statements

if condition {
    // code
} else if otherCondition {
    // code
} else {
    // code
}

// Inline if (ternary)
let result = condition ? "yes" : "no"

Switch Statements

switch value {
case 0:
    print("zero")
case 1, 2:                     // Multiple values
    print("one or two")
case 3...5:                    // Range
    print("three to five")
case let x where x > 5:        // Pattern + condition
    print("greater than 5")
default:
    print("other")
}
// ⚠️ No implicit fallthrough (no break needed)

For Loops

for i in 0..<5 {              // 0 to 4
    print(i)
}

for i in 0...5 {              // 0 to 5 (inclusive)
    print(i)
}

for item in array {
    print(item)
}

for (key, value) in dictionary {
    print("\(key): \(value)")
}

for _ in 1...3 {              // Ignore iterator
    print("repeat")
}

While Loops

while condition {
    // code
}

repeat {
    // code
} while condition             // Do-while equivalent

Loop Control

for i in 0..<10 {
    if i == 5 { break }       // Exit loop
    if i % 2 == 0 { continue } // Skip iteration
}

// Labeled statements
outer: for i in 0..<3 {
    for j in 0..<3 {
        if j == 2 { break outer }
    }
}

Functions

Basic Functions

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

greet(name: "World")          // "Hello, World!"

// Implicit return (single expression)
func add(a: Int, b: Int) -> Int {
    a + b
}

Multiple Parameters

func greet(person: String, from city: String) -> String {
    "Hello \(person) from \(city)!"
}

// External and internal parameter names
greet(person: "Alice", from: "NYC")

Default Parameters

func greet(name: String = "World") -> String {
    "Hello, \(name)!"
}

greet()                        // "Hello, World!"
greet(name: "Alice")          // "Hello, Alice!"

Variadic Parameters

func sum(_ numbers: Int...) -> Int {
    numbers.reduce(0, +)
}

sum(1, 2, 3, 4)               // 10

Inout Parameters

func increment(_ value: inout Int) {
    value += 1
}

var number = 5
increment(&number)             // number is now 6
// ⚠️ Requires & when calling

Function Types

func add(a: Int, b: Int) -> Int {
    a + b
}

let operation: (Int, Int) -> Int = add
operation(2, 3)                // 5

// Function as parameter
func calculate(a: Int, b: Int, op: (Int, Int) -> Int) -> Int {
    op(a, b)
}

calculate(a: 5, b: 3, op: add) // 8

Closures

Basic Syntax

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

greet("World")                 // "Hello, World!"

Shorthand Syntax

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

// Full closure
numbers.map({ (n: Int) -> Int in
    return n * 2
})

// Type inference
numbers.map({ n in
    return n * 2
})

// Implicit return
numbers.map({ n in n * 2 })

// Shorthand argument names
numbers.map({ $0 * 2 })

// Trailing closure
numbers.map() { $0 * 2 }

// Omit parentheses
numbers.map { $0 * 2 }

Capturing Values

func makeIncrementer(increment: Int) -> () -> Int {
    var total = 0
    return {
        total += increment
        return total
    }
}

let inc = makeIncrementer(increment: 5)
inc()                          // 5
inc()                          // 10
inc()                          // 15

Escaping Closures

var handlers: [() -> Void] = []

func addHandler(handler: @escaping () -> Void) {
    handlers.append(handler)
}
// ⚠️ @escaping required when closure outlives function

Structs & Classes

Structs

struct Point {
    var x: Int
    var y: Int

    // Methods
    func distance() -> Double {
        sqrt(Double(x * x + y * y))
    }

    // Mutating methods
    mutating func moveBy(x deltaX: Int, y deltaY: Int) {
        x += deltaX
        y += deltaY
    }
}

var point = Point(x: 0, y: 0) // Auto-generated initializer
point.moveBy(x: 5, y: 5)

Classes

class Person {
    var name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    func greet() -> String {
        "Hi, I'm \(name)"
    }
}

let person = Person(name: "Alice", age: 30)

Computed Properties

struct Rectangle {
    var width: Double
    var height: Double

    var area: Double {
        get { width * height }
        set { width = sqrt(newValue) }
    }

    // Read-only (no set)
    var perimeter: Double {
        2 * (width + height)
    }
}

Property Observers

class StepCounter {
    var steps: Int = 0 {
        willSet {
            print("About to set to \(newValue)")
        }
        didSet {
            print("Changed from \(oldValue) to \(steps)")
        }
    }
}

Static Properties

struct Math {
    static let pi = 3.14159

    static func square(_ x: Int) -> Int {
        x * x
    }
}

Math.pi                        // 3.14159
Math.square(5)                 // 25

Inheritance

class Animal {
    func makeSound() {
        print("Some sound")
    }
}

class Dog: Animal {
    override func makeSound() {
        print("Woof!")
    }
}

// Prevent overriding
final class Cat: Animal { }

Enumerations

Basic Enums

enum Direction {
    case north
    case south
    case east
    case west
}

// Shorthand
enum Direction {
    case north, south, east, west
}

var dir = Direction.north
dir = .south                   // Type inferred

Raw Values

enum Planet: Int {
    case mercury = 1
    case venus = 2
    case earth = 3
}

Planet.earth.rawValue          // 3
Planet(rawValue: 2)            // Optional(Planet.venus)

// String raw values
enum Color: String {
    case red = "RED"
    case green = "GREEN"
}

Color.red.rawValue             // "RED"

Associated Values

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

var code = Barcode.upc(8, 85909, 51226, 3)
code = .qrCode("ABCDEF")

// Extracting values
switch code {
case .upc(let system, let manufacturer, let product, let check):
    print("UPC: \(system)-\(manufacturer)-\(product)-\(check)")
case .qrCode(let productCode):
    print("QR: \(productCode)")
}

Recursive Enums

indirect enum Tree {
    case leaf(Int)
    case node(Tree, Tree)
}

let tree = Tree.node(
    .leaf(1),
    .node(.leaf(2), .leaf(3))
)
// ⚠️ indirect required for recursive types

Enum Methods

enum Status {
    case active, inactive

    mutating func toggle() {
        switch self {
        case .active: self = .inactive
        case .inactive: self = .active
        }
    }
}

var status = Status.active
status.toggle()                // .inactive

Protocols

Protocol Definition

protocol Drawable {
    var area: Double { get }
    func draw()
}

struct Circle: Drawable {
    var radius: Double

    var area: Double {
        .pi * radius * radius
    }

    func draw() {
        print("Drawing circle")
    }
}

Protocol Inheritance

protocol Named {
    var name: String { get }
}

protocol Aged: Named {
    var age: Int { get }
}

struct Person: Aged {
    var name: String
    var age: Int
}

Protocol Composition

protocol Named { }
protocol Aged { }

func greet(_ person: Named & Aged) {
    // Requires both protocols
}

Protocol Extensions

extension Drawable {
    func describe() -> String {
        "Area: \(area)"
    }
}

// All Drawable types now have describe()

Extensions

Adding Methods

extension Int {
    func squared() -> Int {
        self * self
    }
}

5.squared()                    // 25

Adding Computed Properties

extension Double {
    var km: Double { self * 1000 }
    var m: Double { self }
    var cm: Double { self / 100 }
}

let distance = 5.km            // 5000.0

Adding Initializers

extension Rect {
    init(size: Double) {
        self.init(width: size, height: size)
    }
}

Conditional Conformance

extension Array: Drawable where Element == Int {
    var area: Double { Double(count) }
    func draw() { print("Drawing array") }
}
// Only [Int] conforms to Drawable

Error Handling

Defining Errors

enum FileError: Error {
    case notFound
    case permissionDenied
    case unknown
}

Throwing Functions

func readFile(name: String) throws -> String {
    guard name != "" else {
        throw FileError.notFound
    }
    return "File contents"
}

Try-Catch

do {
    let contents = try readFile(name: "data.txt")
    print(contents)
} catch FileError.notFound {
    print("File not found")
} catch FileError.permissionDenied {
    print("Permission denied")
} catch {
    print("Unknown error: \(error)")
}

Optional Try

// Returns nil on error
let contents = try? readFile(name: "data.txt")

// Crashes on error (use only if certain)
let contents = try! readFile(name: "data.txt")
// ⚠️ try! crashes if function throws

Defer

func processFile() {
    let file = openFile()
    defer {
        closeFile(file)        // Always executes before return
    }

    if error { return }
    // closeFile still called
}

Generics

Generic Functions

func swap<T>(_ a: inout T, _ b: inout T) {
    let temp = a
    a = b
    b = temp
}

var x = 1, y = 2
swap(&x, &y)                   // x=2, y=1

Generic Types

struct Stack<Element> {
    private var items: [Element] = []

    mutating func push(_ item: Element) {
        items.append(item)
    }

    mutating func pop() -> Element? {
        items.popLast()
    }
}

var stack = Stack<Int>()
stack.push(1)
stack.push(2)
stack.pop()                    // Optional(2)

Generic Constraints

func findIndex<T: Equatable>(of item: T, in array: [T]) -> Int? {
    for (index, value) in array.enumerated() {
        if value == item {
            return index
        }
    }
    return nil
}
// T must conform to Equatable

Where Clauses

func allEqual<T, U>(_ a: T, _ b: U) -> Bool
    where T: Equatable, U: Equatable, T == U {
    a == b
}

Common Patterns

Map, Filter, Reduce

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

// Map: Transform each element
numbers.map { $0 * 2 }         // [2, 4, 6, 8, 10]

// Filter: Keep elements matching predicate
numbers.filter { $0 % 2 == 0 } // [2, 4]

// Reduce: Combine elements
numbers.reduce(0, +)           // 15
numbers.reduce(1, *)           // 120

CompactMap

let strings = ["1", "2", "three", "4"]
let numbers = strings.compactMap { Int($0) }
// [1, 2, 4] - removes nils

FlatMap

let nested = [[1, 2], [3, 4], [5]]
nested.flatMap { $0 }          // [1, 2, 3, 4, 5]

Chaining

[1, 2, 3, 4, 5]
    .filter { $0 % 2 == 0 }
    .map { $0 * 2 }
    .reduce(0, +)              // 12

Guard Let Pattern

func process(value: Int?) {
    guard let value = value else {
        return
    }
    // value available for rest of function
    print(value)
}

Pattern Matching

let point = (x: 1, y: 2)

switch point {
case (0, 0):
    print("origin")
case (let x, 0):
    print("x-axis at \(x)")
case (0, let y):
    print("y-axis at \(y)")
case (let x, let y) where x == y:
    print("diagonal")
default:
    print("other")
}

Gotchas

Value vs Reference Types

struct Point { var x = 0 }    // Value type (copy)
class Rect { var x = 0 }      // Reference type (shared)

var p1 = Point()
var p2 = p1
p2.x = 5
print(p1.x)                    // 0 (copy)

var r1 = Rect()
var r2 = r1
r2.x = 5
print(r1.x)                    // 5 (reference)

String Indices

let str = "Hello"
// ⚠️ Cannot use Int indices
// str[0]                      // Error!

// Use String.Index
let index = str.index(str.startIndex, offsetBy: 1)
str[index]                     // "e"

// Safe subscripting
if let index = str.firstIndex(of: "l") {
    str[index]                 // "l"
}

Array COW (Copy-on-Write)

var arr1 = [1, 2, 3]
var arr2 = arr1                // Shared storage
arr2.append(4)                 // Now copies
// arr1: [1, 2, 3]
// arr2: [1, 2, 3, 4]

Weak References

class Person {
    var name: String
    weak var friend: Person?   // Prevent retain cycle

    init(name: String) {
        self.name = name
    }
}
// ⚠️ Use weak for delegate patterns

Type Inference Limits

// Can be slow to compile
let result = [1, 2, 3]
    .map { $0 * 2 }
    .filter { $0 > 2 }
    .map { "\($0)" }

// Faster: Add explicit types
let doubled: [Int] = [1, 2, 3].map { $0 * 2 }
let filtered: [Int] = doubled.filter { $0 > 2 }
let strings: [String] = filtered.map { "\($0)" }

Mutating Struct Methods

struct Counter {
    var count = 0
    mutating func increment() {
        count += 1
    }
}

var counter = Counter()
counter.increment()            // OK

let constCounter = Counter()
// constCounter.increment()    // Error: let is immutable
// ⚠️ mutating methods require var

Also see