Author: saqibkhan

  • Swift Closures

    Swift Closures

    Capture values and pass behavior as first-class functions using closure expressions and trailing closure syntax.


    Closure Expressions

    Closures are self-contained blocks of functionality that can be passed and stored.

    Syntax:

    • { (params) -> Return in statements }
    • shorthand args $0$1, and type inference.

    Example

    let nums = [3, 1, 2]
    let sorted = nums.sorted { $0 < $1 }
    let strings = sorted.map { "#\($0)" }
    print(strings) // ["#1", "#2", "#3"]

    This example sorts numbers using a closure with shorthand arguments and maps them to strings.


    Capturing Values

    Closures capture constants and variables from the surrounding context by reference.

    Syntax: func makeCounter() -> () -> Int { var n = 0; return { n += 1; return n } }

    Example

    func makeCounter() -> () -> Int {
      var n = 0
      return {
    
    n += 1
    return n
    } } let next = makeCounter() print(next()) // 1 print(next()) // 2

    The closure remembers n between calls, producing an incrementing counter.



    Trailing Closures

    If the last parameter is a closure, you can use trailing closure syntax for readability.

    Syntax: fn(x) { ... } instead of fn(x, closure: { ... })

    Example

    func repeatTimes(_ n: Int, _ work: () -> Void) {
      for _ in 0..<n { work() }
    }
    
    repeatTimes(3) {
      print("Hi")
    }
  • Swift Enums & Pattern Matching

    Enums & Pattern Matching

    Model finite sets of cases with enum, add associated values, and match using switch with patterns.


    Basic Enums

    Use enum to define a type with a fixed set of cases.

    Syntax: enum Direction { case north, south, east, west }

    Example

    enum Direction { case north, south, east, west }
    
    let d: Direction = .east
    print(d)

    This example defines an enum of directions and creates a value using a short dot syntax.


    Associated Values

    Attach data to each case using associated values.

    Syntax: enum Result { case success(T), failure(Error) }

    Example

    enum Barcode {
      case upc(Int, Int, Int, Int)
      case qr(String)
    }
    
    let b1 = Barcode.upc(8, 85909, 51226, 3)
    let b2 = Barcode.qr("HELLO")

    This example shows a barcode which may be a UPC with four integers or a QR code with a string.



    Pattern Matching

    Use switch with patterns to extract associated values.

    Syntax:

    • switch value { case .case(let x): ... }
    • if case for single-case checks

    Example

    func describe(_ code: Barcode) {
      switch code {
      case .upc(let numberSystem, let manufacturer, let product, let check):
    
    print("UPC: \(numberSystem)-\(manufacturer)-\(product)-\(check)")
    case .qr(let text):
    print("QR: \(text)")
    } } describe(b1) describe(b2)

    This example uses pattern matching to bind associated values and print a formatted description.


    Raw Values

    Provide default raw values (e.g., Int or String) and initialize from them.

    Syntax:

    • enum HTTPStatus: Int { case ok = 200, notFound = 404 }
    • HTTPStatus(rawValue: 200)

    Example

    enum HTTPStatus: Int { case ok = 200, notFound = 404 }
    
    let status = HTTPStatus(rawValue: 200)
    print(status == .ok)
  • Swift Optionals

    Swift Optionals

    Represent missing values safely with optionals, and unwrap them with ??if let, or guard let.


    What Are Optionals?

    An optional is a type that can hold either a value or nil (no value).

    Use ? to declare an optional, and nil-coalescing (??) or binding (if let) to safely read it.

    Syntax:

    • var x: String?
    • x ?? "default"
    • if let v = x { ... }
    • guard let v = x else { return }

    Example

    var nickname: String? = nil
    print(nickname ?? "(none)")
    
    nickname = "Ace"
    if let name = nickname {
      print(name)
    }

    This example prints a default using ?? and unwraps an optional safely with if let.

    Tip: Use guard let inside functions to early-exit on missing values.



    Guard Let

    Use guard let for early exit when required values are missing.

    Example

    func greet(_ input: String?) {
      guard let name = input else {
    
    print("Missing name")
    return
    } print("Hello, \(name)") } greet(nil) greet("Swift")
  • Swift Functions

    Swift Functions

    Define reusable code with parameters and return values; control labels, mutation with inout, defaults, and variadics.


    Defining and Calling Functions

    Use func to define a function with a name, parameters, and return value.

    Syntax:

    • func name(param: Type) -> Return
    • Call with name(param:)

    Example

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

    This example defines a function named greet that takes a String parameter and returns a greeting message.


    Parameters and Return Values

    Use func to define a function with multiple parameters and a return value.

    Syntax:

    • func name(param1: Type, param2: Type) -> Return
    • Multiple params: Separate by commas; annotate types.
    • Parameter labels: External names shown at call sites; use _ to omit.
    • Return type: Use ->; omit for Void.

    Example

    func add(_ a: Int, _ b: Int) -> Int { a + b }
    print(add(2, 3))

    This example omits external parameter labels with _ and returns the sum as an Int.



    Inout, Default Values, Variadics

    Use func to define a function with multiple parameters and a return value.

    Syntax:

    • func name(param: inout Type, default: Type = value)
    • func name(param: Type...)

    Example

    func increment(_ value: inout Int, by step: Int = 1) {
      value += step
    }
    var x = 10
    increment(&x)
    print(x) // 11
    
    func sum(_ nums: Int...) -> Int { nums.reduce(0, +) }
    print(sum(1,2,3))
  • Swift Collection Protocols

    Swift Collection Protocols

    Arrays, Sets and Dictionaries conform to Sequence and Collection, which provide common APIs like count and isEmpty.


    Common APIs

    Use count and isEmpty to check collection size.

    Example

    let arr = [1, 2, 3]
    print(arr.count)
    print(arr.isEmpty)
    let s: Set<Int> = [1, 2, 3]
    print(s.contains(2))
    print(s.isEmpty)

    This example shows shared operations exposed via collection protocols.



    Indices

    Use the indices property to iterate valid positions.

    Example

    let arr = [10, 20, 30]
    for i in arr.indices {
      print("index: \(i), value: \(arr[i])")
    }
  • Swift Mutability

    Mutability (let vs var)

    Use let for constants and var for variables.

    Arrays and dictionaries declared with var can be modified in-place.


    Mutable vs Immutable

    Declare with var when you intend to add/remove elements; use let to prevent mutations.

    Example

    let fixed = [1, 2]
    print(fixed.count)
    var bag = [1, 2]
    bag.append(3)
    print(bag.count)


    Dictionary Mutability

    Mutate dictionaries declared with var by inserting or updating keys.

    Example

    var user = ["name": "Kai"]
    user["city"] = "Oslo"
    print(user.count)
  • Swift Sorting

    Swift Sorting

    Sort arrays with sorted() (returns new) or sort() (in-place). Provide a closure for custom order.


    Sort

    Sort ascending using sorted() and descending in-place using sort(by:).

    Example

    var nums = [3, 1, 2]
    let ascending = nums.sorted()
    print(ascending)      // [1, 2, 3]
    nums.sort(by: >)
    print(nums)           // [3, 2, 1]

    This example sorts ascending using sorted() and descending in-place using sort(by:).



    Case-Insensitive Sort

    Provide a custom closure to sort strings without regard to case.

    Example

    let names = ["bob", "Alice", "dave"]
    let caseInsensitive = names.sorted { $0.lowercased() < $1.lowercased() }
    print(caseInsensitive) // ["Alice", "bob", "dave"]
  • Swift map, filter, reduce

    Swift map, filter, reduce

    Transform and aggregate collections with mapfilter, and reduce.


    Transform and aggregate with map/filter/reduce

    Use map to transform elements, filter to select a subset, and reduce to combine into a single result.

    Example

    let nums = [1, 2, 3, 4]
    let doubled = nums.map { $0 * 2 }
    print(doubled)
    let evens = nums.filter { $0 % 2 == 0 }
    print(evens)
    let sum = nums.reduce(0, +)
    print(sum)


    Convert and Sum

    Use compactMap to convert valid strings to numbers, then reduce to sum.

    Example

    let raw = ["1", "x", "2", "3"]
    let ints = raw.compactMap { Int($0) }   // [1, 2, 3]
    let total = ints.reduce(0, +)
    print(total)

  • Swift Dictionaries

    Swift Dictionaries

    Dictionaries store key-value pairs.

    Lookups are fast by key.

    Use subscripting to read and write values.


    Basics

    Example

    var ages: [String: Int] = ["Kai": 30]
    ages["Elisabeth"] = 25
    print(ages["Kai"] ?? 0)

    This example adds and reads values using dictionary subscripting.



    Iterate Keys and Values

    Loop through a dictionary to access keys and values.

    Example

    let ages = ["Kai": 30, "Elisabeth": 25]
    for k in ages.keys.sorted() {
      print("\(k): \(ages[k]!)")
    }
  • Swift Sets

    Swift Sets

    Sets store unique values with no defined order.

    Test membership with contains, and use union/intersection operations.


    Deduplicate Values

    Use sets to deduplicate values from an array.

    Example

    var letters: Set<Character> = ["a", "b", "a"]
    print(letters.contains("a"))

    This example creates a Set which deduplicates values and checks membership.



    Set Operations

    Combine or compare sets using unionintersection and subtracting.

    Example

    let a: Set<Int> = [1, 2, 3]
    let b: Set<Int> = [3, 4]
    print(a.union(b).sorted())         // [1, 2, 3, 4]
    print(a.intersection(b).sorted())  // [3]
    print(a.subtracting(b).sorted())   // [1, 2]