DevTools

Cheatsheet Swift

Referência completa da linguagem Swift — segura, rápida e moderna para iOS/macOS

Back to languages
Swift
72 cards found
Categories:
Versions:

Basic


9 cards
Variables and Constants
let name = "Swift"       // constant (immutable)
var age = 10             // variable (mutable)
let pi: Double = 3.14    // explicit type
var counter: Int = 0

age = 11                 // OK (var)
// name = "Other"        // ERROR (let)

// let is preferred for safety:
// The compiler warns if a var never changes
// Enables aggressive optimizations

// Multiple declaration:
let x = 1, y = 2, z = 3
var a, b, c: Int         // no initial value

let creates immutable constants — always prefer it. var only when the value changes. Type inference removes redundant declarations. The compiler optimizes let and prevents accidental mutation bugs.

Type Conversions
let x = 42
let s = String(x)        // Int → String
let d = Double(x)        // Int → Double
let f = Float(3.14)      // Double → Float

// String → number (returns Optional!):
let n = Int("123")       // Int? = 123
let inv = Int("abc")     // Int? = nil

// No implicit conversions:
// let y: Double = x     // ERROR!
let y: Double = Double(x) // correct

// Bool → Int does not exist:
// let b = Int(true)     // ERROR!
let b = true ? 1 : 0    // workaround

Swift forbids implicit conversions — it avoids silent bugs. Int("abc") returns nil (no crash). Whenever you convert a String to a number, the result is Optional. Use Double(x) explicitly. There is no Bool→Int conversion.

Ranges and Strides
// Closed range (includes the end):
for i in 1...5 { print(i) }  // 1 2 3 4 5

// Half-open range (excludes the end):
for i in 0..<5 { print(i) }  // 0 1 2 3 4

// Stride with a step:
for i in stride(from: 0, to: 10, by: 2) {
    print(i)  // 0 2 4 6 8
}

// Inclusive stride:
for i in stride(from: 10, through: 0, by: -2) {
    print(i)  // 10 8 6 4 2 0
}

// Ranges the collections:
let nums = Array(1...100)
let slice = nums[5..<10]

// Membership check:
(1...10).contains(5)   // true
(1...10).contains(15)  // false

1...5 = closed (includes 5). 0..<5 = half-open (excludes 5). stride(from:to:by:) for custom steps. through includes the end. Ranges work the collections. contains() checks membership in O(1) for ranges.

Data Types
let integer: Int = 42
let decimal: Double = 3.14159
let flag: Bool = true
let letter: Character = "A"
let text: String = "Swift"

// Tuples:
let http: (Int, String) = (200, "OK")
print(http.0)  // 200
print(http.1)  // "OK"

// Tuples with labels:
let point = (x: 3.0, y: 4.0)
print(point.x) // 3.0

// Numeric types:
// Int, Int8, Int16, Int32, Int64
// UInt, UInt8, UInt16, UInt32, UInt64
// Float (32-bit), Double (64-bit)

Swift has strict types — no implicit conversions. Int and Double are the most used. Character = one Unicode grapheme cluster. Tuples group values without creating a struct. Float = 32 bits, Double = 64 bits (preferred).

Operators
// Arithmetic:
let sum = 5 + 3        // 8
let rem = 10 % 3       // 1
let div = 10 / 3       // 3 (Int division!)
let divD = 10.0 / 3.0  // 3.333...

// Comparison:
5 == 5   // true
5 != 3   // true
5 > 3    // true
5 <= 5   // true

// Logical:
true && false  // false (AND)
true || false  // true  (OR)
!true          // false (NOT)

// Range:
1...5    // 1,2,3,4,5 (closed)
1..<5    // 1,2,3,4   (half-open)

// Compound assignment:
var x = 10
x += 5   // 15
x *= 2   // 30

Integer division truncates: 10 / 3 = 3. Use Double for decimals. ... is a closed range (includes the end). ..< is half-open (excludes the end). Logical operators: &&, ||, !. No ternary operator in complex conditions — prefer if.

Optionals
var name: String? = nil   // can be nil
name = "Swift"

// Safe unwrapping (if let):
if let n = name {
    print(n)  // only runs if non-nil
}

// Optional chaining:
let len = name?.count     // Int? (nil if name is nil)

// Nil-coalescing:
let value = name ?? "default"

// Force unwrap (avoid!):
// let x = name!  // crash if nil!

// Multiple optional binding:
if let a = name, let b = name?.uppercased() {
    print(a, b)
}

Optionals are the central safety mechanism — they force handling absence. if let unwraps safely. ?. chains without crashing. ?? provides a fallback. ! (force unwrap) crashes if nil — always avoid.

Type Aliases and Tuples
typealias UserID = Int
typealias Callback = (String) -> Void
typealias Point = (x: Double, y: Double)

let id: UserID = 42
let p: Point = (x: 3.0, y: 4.0)
print(p.x)  // 3.0

// Tuples the return values:
func divide(_ a: Int, _ b: Int) -> (quot: Int, rem: Int) {
    return (a / b, a % b)
}
let r = divide(17, 5)
print(r.quot)  // 3
print(r.rem)   // 2

// Decomposition:
let (q, rest) = divide(17, 5)

typealias creates semantic names (no runtime cost). Tuples with labels allow access by name. Ideal for simple returns without creating structs. Decomposition with let (a, b) = tuple. Do not overuse — for 3+ fields, prefer a struct.

Strings
let greeting = "Hello"
let name = "World"

// Interpolation (preferred):
let msg = "Hello, \(name)!"

// Concatenation:
let full = greeting + ", " + name

// Multi-line:
let multi = """
    Line 1
    Line 2
    """

// Useful methods:
msg.count              // 13
msg.uppercased()       // HELLO, WORLD!
msg.lowercased()       // hello, world!
msg.contains("World")  // true
msg.hasPrefix("Hello") // true
msg.split(separator: " ")  // ["Hello,", "World!"]

String interpolation (\()) is the preferred form. Triple-quoted (\"\"\") for multiline. Strings are value types and Unicode-correct. count counts characters (not bytes). split returns an array of Substring.

Nil-coalescing and Chaining
let name: String? = nil
let surname: String? = "Silva"

// Nil-coalescing (??):
let display = name ?? "Anonymous"    // "Anonymous"

// Chaining:
let result = name ?? surname ?? "No name"  // "Silva"

// Optional chaining:
let len = name?.count               // nil
let upper = name?.uppercased()      // nil

// Chaining + coalescing:
let size = name?.count ?? 0         // 0

// Multi-level:
struct User { var address: Address? }
struct Address { var city: String? }
let city = user?.address?.city ?? "N/A"

?? provides a default when the optional is nil. Chaining creates cascading fallbacks. ?. chains calls — returns nil if any level is nil. Combining ?. + ?? is the idiomatic pattern. Replaces verbose if-let for simple cases.

Flow Control


9 cards
If / Else
let temp = 25

if temp > 30 {
    print("Hot")
} else if temp > 20 {
    print("Pleasant")
} else {
    print("Cold")
}

// Braces are MANDATORY (even 1 line)
// Parentheses optional in the condition
// The condition MUST be Bool (no Int accepted)

// If the an expression (Swift 5.9+):
let msg = if temp > 25 { "hot" } else { "cold" }

// If-let (optional binding):
if let name = optionalName {
    print(name)  // name unwrapped here
}

Braces {} are mandatory — prevents indentation bugs. The condition must be Bool (does not accept integers like C). if let unwraps optionals. Swift 5.9+ allows if the an expression. Parentheses in the condition are optional.

Guard and Early Exit
func process(name: String?, age: Int?) {
    guard let n = name else {
        print("Name required")
        return  // MUST exit the scope
    }
    guard let i = age, i >= 18 else {
        print("Invalid age")
        return
    }
    // Here n and i are unwrapped:
    print("\(n) is \(i) years old")
}

// Advantage over if-let:
// - Happy path without nesting
// - Variable available in the whole scope
// - Failure condition clear at the top

// guard with throw:
func validate(_ x: Int) throws {
    guard x > 0 else { throw ValidationError.negative }
}

guard checks conditions and exits early if they fail. The else MUST exit the scope (return, throw, break). The unwrapped variable stays available in the rest of the function. Preferred over if-let when you need the value in the whole scope.

Labeled Statements
// Labels on loops:
outer: for i in 1...5 {
    inner: for j in 1...5 {
        if i * j > 12 {
            break outer  // exits the outer loop!
        }
        if j == 3 {
            continue inner  // next j
        }
        print("\(i)×\(j) = \(i*j)")
    }
}

// Label on a switch inside a loop:
loop: while true {
    switch state {
    case .quit:
        break loop  // exits the while!
    case .continue:
        continue loop
    default:
        break  // only exits the switch
    }
}

Labels (name:) identify loops for specific break/continue. break outer exits the outer loop. Without a label, break inside a switch only exits the switch. Essential for nested loops and state machines.

Switch
let day = 3
switch day {
case 1:
    print("Monday")
case 2, 3:
    print("Tuesday or Wednesday")
case 4...6:
    print("Midweek")
default:
    print("Weekend")
}

// MUST be exhaustive (or have default)
// Does NOT fall through automatically
// break is implicit (not needed)

// Explicit fallthrough (rare):
switch day {
case 1:
    print("Start")
    fallthrough
case 2:
    print("Also")
default: break
}

switch must be exhaustive — cover all cases or have a default. No automatic fallthrough (avoids C bugs). Supports ranges (4...6), multiple values (2, 3) and complex patterns. break is implicit.

Pattern Matching
let point = (x: 3, y: -2)
switch point {
case (0, 0):
    print("Origin")
case (_, 0):
    print("X axis")
case (0, _):
    print("Y axis")
case (-2...2, -2...2):
    print("Near the origin")
default:
    print("Point (\(point.x), \(point.y))")
}

// if-case:
if case (let x, 0) = point {
    print("x = \(x)")
}

// for-case:
let data: [Any] = [1, "two", 3.0, "four"]
for case let s the String in data {
    print(s)  // "two", "four"
}

Pattern matching decomposes tuples, checks ranges and uses wildcards (_). if case extracts patterns outside a switch. for case let x the Type filters by type. Powerful for enums with associated values, parsing and state validation.

For-In
// Range:
for i in 1...5 {
    print(i)  // 1 2 3 4 5
}

// Ignore the value:
for _ in 1...3 {
    print("Hello")  // 3x
}

// Collection with index:
let fruits = ["apple", "banana", "cherry"]
for (i, fruit) in fruits.enumerated() {
    print("\(i): \(fruit)")
}

// Dictionary:
let caps = ["PT": "Lisbon", "BR": "Brasília"]
for (country, cap) in caps {
    print("\(country) → \(cap)")
}

// Inline filter (where):
for i in 1...20 where i % 3 == 0 {
    print(i)  // 3 6 9 12 15 18
}

for-in iterates ranges, arrays, dicts, sets. _ ignores the value. enumerated() gives index + value. Dictionaries return (key, value) tuples. where filters inline. There is no for (i=0; i<n; i++) — use ranges.

Ternary and Expressions
let age = 20
let status = age >= 18 ? "adult" : "minor"

// Switch the an expression (Swift 5.9+):
let day = 3
let name = switch day {
    case 1: "Monday"
    case 2: "Tuesday"
    case 3: "Wednesday"
    default: "Other"
}

// If the an expression (Swift 5.9+):
let msg = if age >= 18 {
    "Of age"
} else {
    "Underage"
}

// Chained ternary (avoid!):
// let x = a ? b : c ? d : e  // unreadable

Ternary operator (?:) for simple conditions. Swift 5.9+ allows switch and if the expressions (assign the result). Avoid chaining ternaries — unreadable. Prefer a switch expression for 3+ cases.

While and Repeat-While
// While (checks first):
var n = 5
while n > 0 {
    print(n)
    n -= 1
}

// Repeat-while (runs at least once):
var input: String
repeat {
    input = readLine() ?? ""
    print("Received: \(input)")
} while input != "quit"

// Equivalent to C/Java do-while
// Useful for:
// - Input validation
// - Interactive menus
// - Retry with a condition

// Careful: make sure it terminates!
// var x = 0
// while x < 10 { }  // infinite loop!

while checks first (may never run). repeat-while runs at least once (equivalent to do-while). Ideal for input validation and menus. Make sure the condition eventually becomes false — avoid infinite loops.

Defer
func readFile() throws -> String {
    let file = try openFile("data.txt")

    defer {
        file.close()  // ALWAYS runs
        print("File closed")
    }

    // Even with throw or early return:
    guard file.isValid else {
        throw FileError.invalid
        // defer runs here!
    }

    return try file.read()
    // defer runs here too!
}

// Multiple defer (reverse order):
defer { print("1st") }
defer { print("2nd") }
// Output: "2nd", "1st"

defer runs code when leaving the scope — even with return, throw or break. Ideal for cleanup: closing files, releasing resources, unlock. Multiple defer run in reverse order (LIFO). Equivalent to Java/C# finally.

Functions and Closures


9 cards
Function Declaration
func sum(_ a: Int, _ b: Int) -> Int {
    return a + b
}

// With argument labels:
func greet(to name: String, from sender: String) -> String {
    return "Hello \(name), from \(sender)"
}
greet(to: "Anna", from: "Ray")

// No return value:
func log(_ msg: String) {
    print("[LOG] \(msg)")
}

// Implicit return (Swift 5.1+):
func double(_ x: Int) -> Int { x * 2 }

// Multiple returns (tuple):
func stats(_ nums: [Int]) -> (min: Int, max: Int, avg: Double) {
    (nums.min()!, nums.max()!, Double(nums.reduce(0,+)) / Double(nums.count))
}

func declares functions. External labels make calls self-documenting. _ suppresses the label. Implicit return in single-expression functions. Tuples for multiple returns. -> Void is omitted when there is no return value.

Functions the Types
// Function type:
var operation: (Int, Int) -> Int

operation = { $0 + $1 }
print(operation(3, 4))  // 7

operation = { $0 * $1 }
print(operation(3, 4))  // 12

// Function that returns a function:
func multiplier(_ factor: Int) -> (Int) -> Int {
    return { $0 * factor }
}
let triple = multiplier(3)
triple(5)  // 15

// Function the a parameter:
func apply(_ f: (Int) -> Int, _ x: Int) -> Int {
    f(x)
}
apply({ $0 * 2 }, 5)  // 10

Functions are first-class citizens — they can be stored, passed and returned. The type (Int, Int) -> Int describes the signature. Enables dynamic strategies and composition. Foundation for callbacks, delegates and functional programming.

Generic Functions
func swapValues<T>(_ a: inout T, _ b: inout T) {
    (a, b) = (b, a)
}
var x = 1, y = 2
swapValues(&x, &y)  // x=2, y=1

// With constraints:
func maximum<T: Comparable>(_ a: T, _ b: T) -> T {
    a > b ? a : b
}
maximum(3, 7)      // 7
maximum("a", "z")  // "z"

// Where clause:
func firstEven<T: Collection>(_ c: T) -> T.Element?
    where T.Element: BinaryInteger {
    c.first { $0 % 2 == 0 }
}

// Multiple types:
func zip<A, B>(_ a: [A], _ b: [B]) -> [(A, B)] {
    Array(Swift.zip(a, b))
}

Generic functions work with any type while keeping type safety. <T> declares the type. Constraints (T: Comparable) restrict it. where clause for complex conditions. The compiler specializes for each concrete type (zero-cost).

Special Parameters
// Default values:
func connect(host: String, port: Int = 3306) {
    print("\(host):\(port)")
}
connect(host: "localhost")       // port = 3306
connect(host: "db", port: 5432)  // port = 5432

// Variadic (...):
func average(_ nums: Double...) -> Double {
    nums.reduce(0, +) / Double(nums.count)
}
average(8, 9, 10)  // 9.0

// Inout (pass by reference):
func swapValues(_ a: inout Int, _ b: inout Int) {
    (a, b) = (b, a)
}
var x = 1, y = 2
swapValues(&x, &y)  // x=2, y=1

Default values eliminate overloads. ... (variadic) accepts N arguments. inout passes by reference (modifies the original) — requires & at the call site. Order: normal → default → variadic. One variadic per function.

Escaping and Autoclosure
// @escaping: closure outlives the function
var callbacks: [() -> Void] = []
func register(_ cb: @escaping () -> Void) {
    callbacks.append(cb)  // stored for later
}

// @autoclosure: defers evaluation
func log(level: String, msg: @autoclosure () -> String) {
    if level == "DEBUG" {
        print(msg())  // only evaluates if needed
    }
}
log(level: "INFO", msg: "Data: \(expensiveData())")
// expensiveData() does NOT run if level != DEBUG

// Without @escaping: closure is called INSIDE the function
func execute(_ cb: () -> Void) {
    cb()  // no @escaping needed
}

@escaping indicates the closure will be called after the function returns (callbacks, async). @autoclosure wraps an expression in a closure without {} — enables lazy evaluation. Without @escaping, the closure is called inside the function.

Closures
// Full syntax:
let sum = { (a: Int, b: Int) -> Int in
    return a + b
}

// Type inference:
let double: (Int) -> Int = { $0 * 2 }

// Trailing closure:
let nums = [3, 1, 4, 1, 5]
let sorted = nums.sorted { $0 < $1 }

// Extreme shorthand:
let asc = nums.sorted(by: <)

// Closure capturing variables:
var total = 0
let accumulate = { (x: Int) in total += x }
accumulate(5)
accumulate(3)
print(total)  // 8

Closures are self-contained blocks (lambdas). $0, $1 are shorthand for parameters. Trailing closure simplifies when it is the last argument. sorted(by: <) is the most concise case. Closures capture variables from the enclosing scope by reference.

Throwing Functions
enum ParseError: Error {
    case empty
    case invalid(line: Int)
}

func parse(_ input: String) throws -> [Int] {
    guard !input.isEmpty else { throw ParseError.empty }
    return input.split(separator: ",").enumerated().map { i, s in
        guard let n = Int(s.trimmingCharacters(in: .whitespaces)) else {
            throw ParseError.invalid(line: i + 1)
        }
        return n
    }
}

// Call:
do {
    let nums = try parse("1, 2, 3")
} catch ParseError.invalid(let line) {
    print("Error on line \(line)")
}

// try? (optional) and try! (force):
let nums = try? parse("1,2")  // [Int]?

throws in the signature indicates it can throw errors. throw throws. try calls. do-catch catches specific cases. try? converts to an optional (nil on error). try! crashes on error (avoid). Enums conforming to Error define domains.

Higher-Order Functions
let nums = [1, 2, 3, 4, 5]

// map: transforms each element
let doubles = nums.map { $0 * 2 }       // [2,4,6,8,10]

// filter: selects by condition
let evens = nums.filter { $0 % 2 == 0 } // [2,4]

// reduce: accumulates into one value
let sum = nums.reduce(0) { $0 + $1 }    // 15
let sum2 = nums.reduce(0, +)            // 15

// compactMap: transforms + removes nils
let strs = ["1", "a", "3"].compactMap { Int($0) }
// [1, 3]

// forEach: iterates without returning
nums.forEach { print($0) }

map/filter/reduce are the functional foundation. compactMap discards nils. forEach for side effects. They do not mutate the original collection (they return a new one). Chainable for declarative pipelines. Prefer them over manual loops.

Async Functions
// Asynchronous function:
func fetchData() async throws -> [String] {
    let (data, _) = try await URLSession.shared
        .data(from: url)
    return try JSONDecoder().decode([String].self, from: data)
}

// Call with Task:
Task {
    do {
        let items = try await fetchData()
        print(items)
    } catch {
        print("Error: \(error)")
    }
}

// Multiple calls in parallel:
async let a = fetchA()
async let b = fetchB()
let results = try await [a, b]

// await suspends without blocking the thread

async marks asynchronous functions. await suspends without blocking the thread. Task {} creates an execution context. async let runs in parallel. Replaces completion handlers with readable sequential code. Requires Swift 5.5+.

Collections


9 cards
Arrays
var nums = [1, 2, 3, 4, 5]
nums.append(6)
nums.insert(0, at: 0)
nums.remove(at: 0)
nums[0] = 10

print(nums.count)       // 5
print(nums.isEmpty)     // false
print(nums.first ?? 0)  // 10
print(nums.contains(3)) // true

// Operations:
nums += [7, 8]          // concatenate
let slice = nums[1...3] // ArraySlice
let reversed = nums.reversed()

// Typed:
let names: [String] = ["Anna", "Ray"]
let matrix: [[Int]] = [[1,2], [3,4]]

Arrays are value types with copy-on-write. Typed ([Int] or Array<Int>). append/insert/remove for mutation. first/last return optionals. += concatenates. Slices are views (no copying).

Sorting and Searching
let nums = [5, 2, 8, 1, 9]

let asc = nums.sorted()          // [1,2,5,8,9]
let desc = nums.sorted(by: >)    // [9,8,5,2,1]

// Custom comparator:
struct Person { let name: String; let age: Int }
let people = [Person(name: "Anna", age: 25),
              Person(name: "Ray", age: 30)]
let byAge = people.sorted { $0.age < $1.age }

// Search:
let firstMatch = nums.first { $0 > 4 }   // 5
let index = nums.firstIndex(of: 8)       // Optional(2)
let all = nums.filter { $0 > 3 }         // [5,8,9]

// contains with a condition:
nums.contains { $0 > 8 }  // true

sorted() returns a new array (no mutation). sorted(by:) accepts a custom closure. first(where:) finds the 1st element. firstIndex(of:) returns an Optional. contains(where:) checks existence. Everything is immutable by default.

Custom Collections (Sequence)
// Conform to Sequence:
struct Countdown: Sequence {
    let start: Int

    func makeIterator() -> CountdownIterator {
        CountdownIterator(current: start)
    }
}

struct CountdownIterator: IteratorProtocol {
    var current: Int
    mutating func next() -> Int? {
        guard current > 0 else { return nil }
        defer { current -= 1 }
        return current
    }
}

// Usage:
for n in Countdown(start: 5) {
    print(n)  // 5 4 3 2 1
}

// Gains map, filter, reduce, etc.:
let evens = Countdown(start: 10).filter { $0 % 2 == 0 }

Conforming to Sequence + IteratorProtocol creates custom collections. next() returns nil when finished. Gains all functional operations for free (map, filter, reduce). Ideal for generators, streams and wrappers.

Dictionaries
var capitals = ["PT": "Lisbon", "BR": "Brasília"]

capitals["ES"] = "Madrid"      // add
capitals["PT"] = "Porto"       // update
let removed = capitals.removeValue(forKey: "BR")

// Safe access (returns Optional):
if let cap = capitals["PT"] {
    print(cap)  // "Porto"
}

// Default value:
let value = capitals["XX", default: "N/A"]

// Iteration:
for (country, cap) in capitals {
    print("\(country) → \(cap)")
}

// Keys and values:
let countries = Array(capitals.keys)
let cities = Array(capitals.values)

Dictionaries map unique keys to values. Access by key returns an Optional. default: avoids unwrapping. removeValue(forKey:) removes and returns. Iteration returns (key, value) tuples. Keys must be Hashable.

flatMap and compactMap
// flatMap: flattens nested collections
let lists = [[1,2], [3,4], [5]]
let flat = lists.flatMap { $0 }  // [1,2,3,4,5]

// compactMap: removes nils
let strings = ["1", "abc", "3", "4x"]
let nums = strings.compactMap { Int($0) }  // [1, 3]

// Combined:
let result = lists
    .flatMap { $0 }
    .filter { $0 > 2 }  // [3,4,5]

// Real case: parsing a JSON array
let ids = responses.compactMap { $0["id"] the? Int }

// flatMap with optionals:
let opt: [Int?] = [1, nil, 3, nil, 5]
let valid = opt.compactMap { $0 }  // [1,3,5]

flatMap transforms and flattens nested collections. compactMap is a map that discards nils — essential for parsing. Together they eliminate nested loops and manual checks. compactMap { $0 } removes nils from an array of optionals.

Sets
let primes: Set = [2, 3, 5, 7, 11]
let evens: Set = [2, 4, 6, 8, 10]

// Set operations:
let combined = primes.union(evens)
let common = primes.intersection(evens)     // {2}
let difference = primes.subtracting(evens)  // {3,5,7,11}
let symmetric = primes.symmetricDifference(evens)

// Checks:
primes.contains(5)               // true
primes.isSubset(of: combined)    // true
primes.isDisjoint(with: evens)   // false

// Remove duplicates:
let nums = [1, 2, 2, 3, 3, 3]
let unique = Array(Set(nums))    // [1, 2, 3]

// Insert/remove:
var s: Set<Int> = [1, 2]
s.insert(3)
s.remove(2)

Sets store unique elements with no order. Ideal for membership checks (O(1)) and removing duplicates. Operations: union, intersection, subtracting, symmetricDifference. Require Hashable. No guaranteed order.

Lazy and Performance
let nums = Array(1...1_000_000)

// Eager: creates intermediate arrays
let r1 = nums.filter { $0 % 2 == 0 }
    .map { $0 * 2 }
    .prefix(5)

// Lazy: processes only what is needed
let r2 = nums.lazy
    .filter { $0 % 2 == 0 }
    .map { $0 * 2 }
    .prefix(5)
let result = Array(r2)  // [2,4,6,8,10]

// Without lazy: processes 1M elements
// With lazy: processes ~10 elements

// When to use lazy:
// - Large collections
// - Only need prefix/suffix
// - Pipeline with filter + map

lazy defers computation until needed — processes element by element. Crucial for large collections with prefix. Without lazy: creates intermediate arrays (memory). With lazy: O(k) instead of O(n). Convert with Array() at the end.

Functional Operations
let nums = [1, 2, 3, 4, 5, 6]

let doubles = nums.map { $0 * 2 }
let evens = nums.filter { $0 % 2 == 0 }
let sum = nums.reduce(0, +)  // 21

// joined:
let text = nums.map(String.init)
    .joined(separator: ", ")
// "1, 2, 3, 4, 5, 6"

// Chaining (pipeline):
let result = nums
    .filter { $0 > 2 }
    .map { $0 * 10 }
    .reduce(0, +)
// 30+40+50+60 = 180

// sorted + prefix:
let top3 = nums.sorted(by: >).prefix(3)  // [6,5,4]

map/filter/reduce for declarative transformations. Chaining creates readable pipelines. joined converts to a string. sorted(by:) + prefix for top-N. They return new arrays (no mutation). Prefer them over manual loops.

Dictionary Operations
var scores = ["Anna": 85, "Ray": 92, "Mia": 78]

// Update with default:
scores["Anna", default: 0] += 5  // 90

// mapValues (keeps keys):
let bonus = scores.mapValues { $0 + 10 }

// filter:
let passed = scores.filter { $0.value >= 80 }

// merge:
let extras = ["Zé": 70]
scores.merge(extras) { old, new in new }

// Group (grouping):
let nums = [1, 2, 3, 4, 5, 6]
let groups = Dictionary(grouping: nums) { $0 % 2 == 0 ? "even" : "odd" }
// ["even": [2,4,6], "odd": [1,3,5]]

// Build from arrays:
let keys = ["a", "b", "c"]
let vals = [1, 2, 3]
let dict = Dictionary(uniqueKeysWithValues: zip(keys, vals))

default: for updates without checking existence. mapValues transforms values keeping keys. merge combines dicts with a conflict closure. Dictionary(grouping:by:) groups by criterion. zip + uniqueKeysWithValues builds a dict from arrays.

Classes e Structs


9 cards
Structs
struct Point {
    var x: Double
    var y: Double

    func distance(to other: Point) -> Double {
        let dx = x - other.x
        let dy = y - other.y
        return (dx*dx + dy*dy).squareRoot()
    }
}

// Automatic memberwise init:
var p = Point(x: 3, y: 4)

// Value type (independent copy):
var q = p
q.x = 10
print(p.x)  // 3 (unchanged!)

// Mutation requires var:
p.x = 5  // OK (var)

struct is a value type — each copy is independent. Gets a memberwise init for free. Preferred for data models. Mutation requires var. Copy-on-write for efficiency. It is the most used type in modern Swift.

Extensions
extension Int {
    var isEven: Bool { self % 2 == 0 }
    var squared: Int { self * self }

    func repeated(_ times: Int) {
        for _ in 0..<times { print(self) }
    }
}

4.isEven      // true
5.squared     // 25
3.repeated(2) // prints 3 twice

// String extension:
extension String {
    var capitalizedFirst: String {
        prefix(1).uppercased() + dropFirst()
    }
}
"swift".capitalizedFirst  // "Swift"

extension adds functionality to existing types (including system ones). Can add computed properties, methods and protocol conformance. Cannot add stored properties. Ideal for utilities and DSLs.

Mutating and Static
struct Counter {
    var value = 0

    // mutating: modifies self in a struct
    mutating func increment() {
        value += 1
    }

    mutating func reset() {
        self = Counter()  // replace self
    }
}

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

// Static (type, not instance):
struct Math {
    static let pi = 3.14159
    static func double(_ x: Int) -> Int { x * 2 }
}
Math.pi         // 3.14159
Math.double(5)  // 10

// In classes: class func (overridable)

mutating allows struct methods to modify properties. Without mutating, struct methods are read-only. static belongs to the type (not the instance). class func in classes is overridable. self = ... replaces the whole struct.

Classes and Inheritance
class Animal {
    let name: String
    init(name: String) { self.name = name }
    func sound() -> String { "..." }
}

class Dog: Animal {
    override func sound() -> String { "Woof!" }
}

let c = Dog(name: "Rex")
print(c.sound())  // "Woof!"

// Reference type (shared):
let a = c
a.name  // "Rex" — same object!

// Deinitializer:
class File {
    deinit { print("Closed") }
}

// Check type:
c is Animal      // true
c the? Animal     // Animal?

class is a reference type — multiple variables point to the same object. Supports inheritance (single base), override and deinit. is checks the type, the? casts. Use when you need shared identity or inheritance.

Protocol Extensions
protocol Numeric {
    var value: Double { get }
}

// Default implementation:
extension Numeric {
    var squared: Double { value * value }
    func description() -> String {
        "Value: \(value), Square: \(squared)"
    }
}

struct Coin: Numeric {
    let value: Double
}
Coin(value: 5).squared  // 25.0

// Retroactive conformance:
extension Int: Numeric {
    var value: Double { Double(self) }
}
42.description()  // "Value: 42.0, Square: 1764.0"

Protocol extensions provide default implementations — any conforming type gets the methods for free. Enables retroactive conformance (conforming existing types). Foundation of POP — an alternative to classic inheritance. Composition > inheritance.

Protocols
protocol Describable {
    var description: String { get }
    func summarize() -> String
}

struct Book: Describable {
    let title: String
    var description: String { "Book: \(title)" }
    func summarize() -> String { title }
}

// Protocol the a type:
let items: [any Describable] = [Book(title: "Swift")]

// Multiple conformance:
struct Product: Describable, Codable, Hashable {
    // implement all
}

// Protocol composition:
func show(_ item: Describable & Codable) { }

protocol defines contracts without implementation. Any type can conform. any Protocol (existential) for heterogeneous collections. Composition with & requires multiple protocols. Foundation of Protocol-Oriented Programming.

Properties and Observers
struct Circle {
    var radius: Double

    // Computed property:
    var area: Double { .pi * radius * radius }

    // Getter/Setter:
    var diameter: Double {
        get { radius * 2 }
        set { radius = newValue / 2 }
    }
}

// Property observers:
class Config {
    var volume: Int = 50 {
        willSet { print("From \(volume) to \(newValue)") }
        didSet { print("Changed from \(oldValue)") }
    }
}

// Lazy (computed on 1st access):
struct DB {
    lazy var connection = Connection()  // only created when used
}

Computed properties calculate on demand. willSet/didSet observe changes. lazy defers initialization until first access. newValue and oldValue are implicit. Ideal for validation, logging and caching.

Enums with Associated Values
enum LoadResult {
    case success(data: String)
    case error(code: Int, msg: String)
    case loading
}

let r = LoadResult.success(data: "JSON")

switch r {
case .success(let data):
    print("Data: \(data)")
case .error(let code, let msg):
    print("Error \(code): \(msg)")
case .loading:
    print("Please wait...")
}

// Raw values:
enum HTTPMethod: String {
    case get = "GET"
    case post = "POST"
}
HTTPMethod.get.rawValue  // "GET"

Enums in Swift are powerful — each case can carry associated values of different types. They replace class hierarchies for states. Pattern matching in switch extracts values. Raw values for simple enums (String, Int).

Subscripts
struct Matrix {
    let rows: Int, cols: Int
    var data: [Double]

    subscript(row: Int, col: Int) -> Double {
        get { data[row * cols + col] }
        set { data[row * cols + col] = newValue }
    }
}

var m = Matrix(rows: 2, cols: 2, data: [1,2,3,4])
m[0, 1]      // 2.0
m[1, 0] = 9  // set

// Subscript with a different type:
extension String {
    subscript(i: Int) -> Character {
        self[index(startIndex, offsetBy: i)]
    }
}
"Swift"[0]  // "S"

subscript allows index access like arrays. Can have multiple parameters and types. Getter and setter are optional. Ideal for matrices, grids and custom collections. Natural syntax: m[0, 1] instead of m.get(0, 1).

Advanced


9 cards
Advanced Generics
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()  // 2

// Associated types:
protocol Container {
    associatedtype Item
    mutating func add(_ item: Item)
    var count: Int { get }
}

// Opaque types (some):
func makeShape() -> some Shape {
    Circle(radius: 5)  // concrete type hidden
}

Generics enable reusable code with type safety. associatedtype in protocols defines abstract types. some Protocol (opaque type) hides the concrete type while keeping performance. any Protocol (existential) allows heterogeneity.

Property Wrappers
@propertyWrapper
struct Clamped {
    private var value: Int
    let range: ClosedRange<Int>

    var wrappedValue: Int {
        get { value }
        set { value = min(max(newValue, range.lowerBound), range.upperBound) }
    }

    init(wrappedValue: Int, range: ClosedRange<Int>) {
        self.range = range
        self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
    }
}

struct Config {
    @Clamped(range: 0...100) var volume = 50
}

var c = Config()
c.volume = 150
print(c.volume)  // 100 (clamped!)

Property wrappers encapsulate reusable getter/setter logic. @Clamped restricts values automatically. wrappedValue is the property. Used in SwiftUI: @State, @Binding, @ObservedObject. They eliminate repetitive validation.

Sendable and Data Races
// Sendable: type safe for concurrency
struct Point: Sendable {
    let x, y: Double
}

// Structs with let are Sendable automatically
// Classes need @unchecked or actor

// @Sendable closure:
func execute(_ work: @Sendable () async -> Void) {
    Task { await work() }
}

// Non-Sendable (careful!):
class Cache {  // NOT Sendable
    var data: [String: Any] = [:]
}

// Solution: actor
actor SafeCache {
    var data: [String: Any] = [:]
}

// Swift 6: strict concurrency checking
// Data races = compile error!

Sendable marks types safe to pass between tasks. Immutable structs are Sendable automatically. Mutable classes are NOT — use actor. @Sendable on closures. Swift 6 turns data races into compile errors (strict concurrency).

Advanced Error Handling
enum NetworkError: Error, LocalizedError {
    case noConnection
    case timeout(seconds: Int)
    case server(code: Int)

    var errorDescription: String? {
        switch self {
        case .noConnection: "No connection"
        case .timeout(let s): "Timeout: \(s)s"
        case .server(let c): "Error \(c)"
        }
    }
}

// try? and try!:
let data = try? fetch()   // Optional
let data2 = try! fetch()  // crashes on error!

// rethrows:
func process(_ f: () throws -> Int) rethrows -> Int {
    try f()
}

// Never (does not return):
func fatalError(_ msg: String) -> Never {
    print(msg)
    exit(1)
}

LocalizedError adds readable messages. try? converts to an optional. try! crashes (avoid). rethrows only throws if the argument throws. Never indicates it does not return. Enums with associated values for rich errors.

Result Builders
@resultBuilder
struct HTMLBuilder {
    static func buildBlock(_ parts: String...) -> String {
        parts.joined(separator: "\n")
    }

    static func buildOptional(_ part: String?) -> String {
        part ?? ""
    }
}

func html(@HTMLBuilder content: () -> String) -> String {
    "<html>\n\(content())\n</html>"
}

let showFooter = true
let page = html {
    "<h1>Title</h1>"
    "<p>Content</p>"
    if showFooter {
        "<footer>End</footer>"
    }
}

Result builders enable declarative syntax (DSL) — the foundation of SwiftUI. buildBlock combines expressions. buildOptional supports if. The compiler transforms the block into builder calls. Used in SwiftUI, Vapor (HTML) and custom DSLs.

Async/Await and TaskGroup
// Structured concurrency:
func fetchAll(urls: [URL]) async throws -> [Data] {
    try await withThrowingTaskGroup(of: Data.self) { group in
        for url in urls {
            group.addTask {
                try await URLSession.shared.data(from: url).0
            }
        }
        return try await group.reduce(into: []) { $0.append($1) }
    }
}

// Task with priority:
Task(priority: .high) {
    let data = try await fetchData()
}

// Sleep:
try await Task.sleep(for: .seconds(2))

// Cancellation:
let task = Task { try await work() }
task.cancel()

TaskGroup runs tasks in parallel with unified handling. withThrowingTaskGroup for throwing functions. Task(priority:) sets the priority. Task.sleep suspends. task.cancel() cancels. Structured concurrency = no callbacks.

Memory Management (ARC)
// ARC: Automatic Reference Counting
class Node {
    let value: Int
    var next: Node?       // strong ref
    weak var prev: Node?  // weak ref (not counted!)

    init(_ v: Int) { value = v }
    deinit { print("Node \(value) released") }
}

var a: Node? = Node(1)
var b: Node? = Node(2)
a?.next = b       // strong: b retained
b?.prev = a       // weak: does not retain a

a = nil           // Node 1 released (no strong refs)
b = nil           // Node 2 released

// Closures: capture list
var handler: (() -> Void)?
let obj = MyObject()
handler = { [weak obj] in
    guard let obj else { return }
    obj.doWork()
}

ARC counts strong references. When it reaches 0, it releases. weak is not counted (avoids cycles). unowned is like weak but crashes if nil. Closures capture strong by default — use [weak self] to avoid retain cycles. deinit for cleanup.

Actors
actor BankAccount {
    var balance: Double = 0

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

    func withdraw(_ amount: Double) throws -> Double {
        guard balance >= amount else {
            throw BankError.insufficient
        }
        balance -= amount
        return balance
    }
}

// Access requires await:
let account = BankAccount()
await account.deposit(100)
let newBalance = try await account.withdraw(50)

// MainActor (UI thread):
@MainActor
class ViewModel: ObservableObject {
    @Published var items: [String] = []
}

actor automatically protects mutable state from data races. Only one task accesses the state at a time. External access requires await. @MainActor guarantees execution on the main thread (UI). Replaces manual locks with compiler safety.

Macros (Swift 5.9+)
// Macros generate code at compile time:

// Attached macro:
@Observable
class ViewModel {
    var items: [String] = []
    var selected: String?
}
// Generates: automatic observation tracking

// Freestanding macro:
let url = #URL("https://swift.org")
// Validates the URL at compile time!

// #Preview macro (SwiftUI):
#Preview {
    ContentView()
}

// Custom macro (syntax):
// @attached(member)
// public macro Model() = #externalMacro(...)

// Macros are expanded at compile time
// (not at runtime) — zero overhead

Macros (Swift 5.9+) generate code at compile time. @Observable replaces ObservableObject. #URL validates at compile time. #Preview for SwiftUI. Attached (@) vs freestanding (#). Zero overhead — expanded by the compiler.

Installation and Setup


9 cards
Install Xcode (macOS)
// 1. Install Xcode from the App Store (free)
// 2. Install Command Line Tools:
xcode-select --install

// 3. Verify installation:
swift --version
// Swift version 6.0 (swiftlang-6.0.0)

// 4. Accept the license:
sudo xcodebuild -license accept

// Xcode includes:
// - Swift compiler (swiftc)
// - REPL (swift)
// - Package Manager (swift package)
// - iOS/watchOS/tvOS simulators
// - Interface Builder and SwiftUI Preview

Xcode is the official IDE (macOS only). xcode-select --install installs the CLI tools. swift --version confirms the installation. It includes compiler, REPL, simulators and Swift Package Manager. Required for iOS/macOS development.

Dependencies (SPM)
// Package.swift
// swift-tools-version: 6.0
import PackageDescription

let package = Package(
    name: "MyApp",
    dependencies: [
        .package(url: "https://github.com/Alamofire/Alamofire.git",
                 from: "5.9.0"),
        .package(url: "https://github.com/apple/swift-log.git",
                 from: "1.5.0"),
    ],
    targets: [
        .executableTarget(
            name: "MyApp",
            dependencies: ["Alamofire",
                           .product(name: "Logging",
                                    package: "swift-log")]
        )
    ]
)

Package.swift declares dependencies with .package(url:from:). from: uses semantic versioning. .product(name:package:) when the product name differs from the package. swift package resolve downloads them. Dependencies live in .build/.

Essential Tools
// sourcekit-lsp: language server (editors)
// Integrated in Xcode, VS Code, Neovim

// swift-format: official formatter
swift format --in-place Sources/

// swift-docc: documentation
swift package generate-documentation

// Instruments: profiling (Xcode)
// Product → Profile → Time Profiler

// lldb: debugger
$ lldb ./app
(lldb) breakpoint set --line 10
(lldb) run
(lldb) print variable
(lldb) po object  // object description

// swift-testing (Swift 6):
// import Testing
// @Test func test() { #expect(2 + 2 == 4) }

sourcekit-lsp gives autocomplete in editors. swift-format formats code. Instruments does profiling (memory, CPU). lldb is the debugger (po prints objects). swift-testing is the modern testing framework (replaces XCTest).

Swift on Linux/Windows
// Linux (Ubuntu/Debian):
// 1. Download at swift.org/download
// 2. Extract and add to PATH:
export PATH=/usr/local/swift/usr/bin:$PATH

// 3. Verify:
swift --version

// Windows:
// 1. Install Visual Studio 2022 (C++ workload)
// 2. Download the installer at swift.org
// 3. Install and use via Developer Command Prompt

// Docker:
docker run --rm swift:6.0 swift --version

// Note: SwiftUI/UIKit only available on macOS
// On Linux: Foundation, networking, server-side

Swift is open-source and works on Linux and Windows. Download at swift.org. Docker has official images. On Linux/Windows: no SwiftUI/UIKit (only server-side and CLI). Ideal for backend with Vapor or Hummingbird.

Hello World and Structure
// main.swift (or top-level in scripts)
import Foundation

print("Hello, World!")

// No explicit main() in scripts
// In SPM executable: main.swift or @main

// With @main (Swift 5.3+):
@main
struct App {
    static func main() {
        print("Hello with @main!")
    }
}

// Comments:
// Single line
/* Multi-line
   /* nested! */ */
/// Documentation (shows in Quick Help)

print() is the output function. Scripts run top-level without main(). @main defines the entry point in SPM projects. import Foundation for advanced basic types. Comments: //, /* */ (nestable), /// for documentation.

Swift REPL and Scripts
// Interactive REPL:
$ swift
Welcome to Swift!
1> let x = 42
2> print(x * 2)
84
3> :quit

// Script (.swift file):
// hello.swift
print("Hello, Swift!")
let nums = [1, 2, 3]
print(nums.map { $0 * 2 })

// Run:
swift hello.swift

// Compile to binary:
swiftc hello.swift -o hello
./hello

// Optimized mode:
swiftc -O hello.swift -o hello_release

swift opens the interactive REPL. swift file.swift runs scripts. swiftc compiles to a native binary. -O enables optimizations. The REPL is ideal for experimenting. Scripts do not need main() — top-level code runs directly.

Xcode: Create a Project
// 1. Xcode → File → New → Project
// 2. Choose a template:
//    - App (iOS/macOS) → SwiftUI or UIKit
//    - Command Line Tool → CLI
//    - Framework → library
//    - Package → SPM

// 3. Configure:
//    Product Name: MyApp
//    Organization: com.company
//    Interface: SwiftUI
//    Language: Swift

// 4. Project structure:
//    MyApp/
//    ├── MyApp.swift       → @main entry
//    ├── ContentView.swift → main UI
//    ├── Assets.xcassets   → images/colors
//    └── Info.plist        → configuration

// 5. Run: Cmd+R (simulator)

Xcode creates projects from templates. SwiftUI is the modern UI framework. Cmd+R builds and runs in the simulator. ContentView.swift is the main view. Assets.xcassets manages images and colors. Info.plist holds app configuration.

Swift Package Manager
// Create an executable package:
swift package init --type executable
cd MyApp

// Create a library:
swift package init --type library

// Structure:
// Package.swift       → manifest
// Sources/            → source code
// Tests/              → tests
// .build/             → artifacts (gitignore)

// Commands:
swift build             // compile
swift run               // compile + run
swift test              // run tests
swift package resolve   // resolve dependencies
swift package update    // update dependencies

swift package init creates a project with the standard structure. Package.swift is the manifest (dependencies, targets). swift build compiles, swift run executes. swift test runs tests. Replaces Xcode projects for CLI and server-side.

Compilation and Optimization
// Compile a single file:
swiftc main.swift -o app

// Multiple files:
swiftc *.swift -o app

// Optimizations:
swiftc -O main.swift -o app        // optimize
swiftc -Ounchecked main.swift      // no checks (risky!)

// Debug info:
swiftc -g main.swift -o app

// Modules:
swiftc -emit-module -module-name MyLib *.swift

// See compile time:
swiftc -Xfrontend -debug-time-function-bodies main.swift

// Whole Module Optimization (SPM):
// swift build -c release

swiftc is the compiler. -O enables optimizations (release). -g adds debug info. -Ounchecked removes checks (dangerous). swift build -c release compiles with WMO. Swift compiles to native code via LLVM.

SwiftUI and Ecosystem


9 cards
SwiftUI: First View
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(spacing: 16) {
            Text("Hello, SwiftUI!")
                .font(.largeTitle)
                .foregroundColor(.blue)

            Button("Tap") {
                print("Tapped!")
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}

// App entry:
@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

SwiftUI is declarative — you describe the UI, not imperative. body returns some View. VStack/HStack/ZStack for layout. Chainable modifiers (.font, .padding). @main + WindowGroup is the entry point.

URLSession (Networking)
// GET with async/await:
func fetchUsers() async throws -> [User] {
    let url = URL(string: "https://api.com/users")!
    let (data, response) = try await URLSession.shared
        .data(from: url)

    guard let http = response the? HTTPURLResponse,
          http.statusCode == 200 else {
        throw NetworkError.server(code: 500)
    }

    return try JSONDecoder().decode([User].self, from: data)
}

// POST:
func create(user: User) async throws {
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json",
                     forHTTPHeaderField: "Content-Type")
    request.httpBody = try JSONEncoder().encode(user)
    let _ = try await URLSession.shared.data(for: request)
}

URLSession.shared.data(from:) with async/await. Check HTTPURLResponse and the status code. JSONDecoder for parsing. POST: set httpMethod, headers and httpBody. Always handle errors with throws. Replaces completion handlers.

Deploy and Distribution
// iOS App Store:
// 1. Xcode → Product → Archive
// 2. Organizer → Distribute App
// 3. App Store Connect (upload)
// 4. TestFlight (beta testing)

// Certificates and Profiles:
// - Apple Developer Account ($99/year)
// - Signing & Capabilities (Xcode)
// - Provisioning Profiles

// macOS:
// - Mac App Store or notarization
// - xcrun notarytool submit app.zip

// CI/CD:
// xcodebuild -scheme MyApp -sdk iphonesimulator
// xcodebuild test -scheme MyApp -destination "platform=iOS Simulator,name=iPhone 16"

// fastlane:
// fastlane beta  // upload TestFlight

iOS distribution requires an Apple Developer Account. Archive + Organizer for upload. TestFlight for beta. Signing with certificates and profiles. macOS: notarization with notarytool. CI/CD with xcodebuild or fastlane.

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

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

// @Binding: pass state to a child
struct ChildView: View {
    @Binding var value: Int

    var body: some View {
        Button("Reset") { value = 0 }
    }
}

// Usage:
struct ParentView: View {
    @State private var count = 0
    var body: some View {
        ChildView(value: $count)  // $ = binding
    }
}

@State manages local view state (private). Changes re-render automatically. @Binding passes a mutable reference to a child. $count creates a binding. State is the source of truth. Always private for @State.

Combine (Reactive)
import Combine

class ViewModel: ObservableObject {
    @Published var searchText = ""
    @Published var results: [String] = []
    private var cancellables = Set<AnyCancellable>()

    init() {
        $searchText
            .debounce(for: .milliseconds(300), scheduler: RunLoop.main)
            .removeDuplicates()
            .filter { !$0.isEmpty }
            .sink { [weak self] query in
                self?.search(query)
            }
            .store(in: &cancellables)
    }

    func search(_ q: String) {
        results = ["Result: \(q)"]
    }
}

Combine is the Apple reactive framework. @Published emits changes. debounce waits for a pause. removeDuplicates avoids repetitions. sink subscribes. store(in:) keeps the subscription alive. Alternative: AsyncSequence (more modern).

Navigation
struct ListView: View {
    let items = ["Swift", "SwiftUI", "Combine"]

    var body: some View {
        NavigationStack {
            List(items, id: \.self) { item in
                NavigationLink(value: item) {
                    Text(item)
                }
            }
            .navigationTitle("Technologies")
            .navigationDestination(for: String.self) { item in
                DetailView(title: item)
            }
        }
    }
}

struct DetailView: View {
    let title: String
    var body: some View {
        Text(title)
            .navigationTitle(title)
    }
}

NavigationStack (iOS 16+) manages navigation. NavigationLink(value:) + navigationDestination(for:) = type-safe navigation. List for scrollable lists. navigationTitle sets the title. Replaces NavigationView (deprecated).

Testing
import Testing

// swift-testing (Swift 6 / Xcode 16):
@Test func correctSum() {
    #expect(sum(2, 3) == 5)
}

@Test("Email validation")
func validEmail() {
    #expect(validate("ana@mail.com") == true)
    #expect(validate("invalid") == false)
}

// XCTest (classic):
import XCTest

class MathTests: XCTestCase {
    func testSum() {
        XCTAssertEqual(sum(2, 3), 5)
    }

    func testError() throws {
        XCTAssertThrowsError(try parse("")) { error in
            XCTAssertEqual(error the? ParseError, .empty)
        }
    }
}

swift-testing is the modern framework (macros, @Test, #expect). XCTest is the classic one (XCTAssertEqual). Both run with swift test or Xcode. Test edge cases, errors and integration. @Test with a description for clarity.

Codable (JSON)
struct User: Codable {
    let id: Int
    let name: String
    let email: String
}

// Decode (JSON → Struct):
let json = """
{"id": 1, "name": "Anna", "email": "ana@mail.com"}
""".data(using: .utf8)!

let user = try JSONDecoder().decode(User.self, from: json)

// Encode (Struct → JSON):
let data = try JSONEncoder().encode(user)
let str = String(data: data, encoding: .utf8)

// CodingKeys (map names):
struct Post: Codable {
    let title: String
    let creationDate: Date

    enum CodingKeys: String, CodingKey {
        case title
        case creationDate = "created_at"
    }
}

Codable = Encodable + Decodable. JSONDecoder converts JSON → struct. JSONEncoder does the opposite. CodingKeys maps different names. Automatic for simple types. Essential for REST APIs and persistence.

SwiftData (Persistence)
import SwiftData

@Model
class Post {
    var title: String
    var content: String
    var creationDate: Date

    init(title: String, content: String) {
        self.title = title
        self.content = content
        self.creationDate = .now
    }
}

// In the App:
@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup { ContentView() }
            .modelContainer(for: Post.self)
    }
}

// In the View:
struct ListView: View {
    @Query(sort: \Post.creationDate, order: .reverse)
    var posts: [Post]

    @Environment(\.modelContext) var context

    func add() {
        context.insert(Post(title: "New", content: "..."))
    }
}

SwiftData (iOS 17+) is the modern Apple ORM. @Model defines entities. @Query fetches with sorting/filtering. modelContext for insert/delete. .modelContainer(for:) configures it. Replaces Core Data with native SwiftUI syntax.