🦅 Swift Cheat Sheet

Modern Swift — optionals, protocols, generics, Combine, async/await.

🔍
📦 Types & Variables
Variable declarations
var name = "Swift"           // mutable
let pi = 3.14159             // immutable

var age: Int = 25
let city: String = "Bangkok"
var score: Double = 9.5
var isActive: Bool = true
String interpolation & multi-line
let greeting = "Hello, \(name)!"
let calc = "Result: \(2 + 2)"
let multi = """
  Multi-line
  string
  """
Enum
enum Direction { case north, south, east, west }

// Raw values
enum Status: String {
  case active   = "active"
  case inactive = "inactive"
  var isActive: Bool { self == .active }
}

// Associated values
enum Result<T> {
  case success(T)
  case failure(Error)
}

let result: Result<User> = .success(user)
switch result {
case .success(let u): print(u.name)
case .failure(let e): print(e)
}
Type casting
let n = value as? Int         // optional cast (nil if fails)
let n2 = value as! Int        // force cast (crash if fails)
if value is String { ... }    // type check
❓ Optionals
Optional basics
var name: String? = nil
name = "Feem"

// Unwrapping
if let n = name { print(n) }           // if let
guard let n = name else { return }     // guard let — early exit
let n = name!                          // force unwrap (avoid!)
let n = name ?? "default"             // nil-coalescing
Optional chaining
let city = user?.address?.city         // String?
user?.updateProfile()                  // call method safely

// Multiple bindings
if let name = user?.name, let age = user?.age, age >= 18 {
  print("Adult: \(name)")
}
Optional pattern in switch
switch optionalValue {
case .some(let v): print(v)
case .none:        print("nil")
}

// or
switch optionalValue {
case let v?:  print(v)
case nil:     print("nil")
}
📚 Collections
Array
var list: [String] = ["a", "b", "c"]
list.append("d")
list.insert("x", at: 0)
list.remove(at: 1)
list.count; list.isEmpty
list.first; list.last
list.contains("a")
list.sorted()
list.reversed()

// Functional
list.map { $0.uppercased() }
list.filter { $0.count > 1 }
list.reduce("") { $0 + $1 }
list.compactMap { Int($0) }       // map + remove nil
list.flatMap { [$0, $0] }         // flatten
list.first { $0.hasPrefix("a") }
list.enumerated().forEach { i, v in print(i, v) }
Dictionary
var dict: [String: Int] = ["a": 1, "b": 2]
dict["c"] = 3
dict.removeValue(forKey: "a")
dict["missing"]              // Optional (Int?)
dict["missing", default: 0]  // non-optional with default
dict.keys.sorted()
dict.values.map { $0 * 2 }
dict.filter { $1 > 1 }
dict.mapValues { $0 * 10 }
Set
var set: Set<Int> = [1, 2, 3, 3]   // {1, 2, 3}
set.insert(4)
set.remove(2)
set.contains(3)
set.union([4, 5])
set.intersection([2, 3, 4])
🔧 Functions
Function syntax
// Basic
func add(_ a: Int, _ b: Int) -> Int { a + b }

// Argument labels
func greet(name: String, age: Int = 0) { print("Hi \(name)") }
greet(name: "Feem", age: 30)

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

// inout
func double(_ n: inout Int) { n *= 2 }
double(&myNum)

// Multiple returns via tuple
func minMax(_ arr: [Int]) -> (min: Int, max: Int) {
  (arr.min()!, arr.max()!)
}
let result = minMax([1,2,3])
print(result.min, result.max)
@discardableResult & throws
enum NetworkError: Error {
  case notFound
  case unauthorized(String)
}

func fetchData() throws -> Data {
  guard isConnected else { throw NetworkError.notFound }
  return Data()
}

// Call with do-catch
do {
  let data = try fetchData()
} catch NetworkError.notFound {
  print("Not found")
} catch NetworkError.unauthorized(let msg) {
  print("Auth error: \(msg)")
} catch {
  print("Unknown: \(error)")
}

// try? returns optional
let data = try? fetchData()
// try! force (crash on error)
let data2 = try! fetchData()
🔒 Closures
Closure syntax
// Full syntax
let multiply: (Int, Int) -> Int = { (a, b) in return a * b }

// Shorthand
let multiply2: (Int, Int) -> Int = { $0 * $1 }

// Trailing closure
[1,2,3].sorted { $0 > $1 }

// Escaping closure (stored / async)
func fetchUser(completion: @escaping (User?) -> Void) {
  DispatchQueue.global().async {
    let user = User(name: "Feem")
    DispatchQueue.main.async { completion(user) }
  }
}

// Capture list (avoid retain cycles)
button.action = { [weak self] in
  guard let self else { return }
  self.handleTap()
}
🏗️ OOP
Struct vs Class
// Struct — value type (prefer for data)
struct Point {
  var x: Double
  var y: Double

  // Mutating method
  mutating func move(dx: Double, dy: Double) {
    x += dx; y += dy
  }
}

// Class — reference type (use for shared mutable state)
class ViewModel: ObservableObject {
  var items: [Item] = []

  deinit { print("deallocated") }  // cleanup
}
Inheritance
class Animal {
  var name: String
  init(name: String) { self.name = name }
  func speak() { print("\(name) makes a sound") }
}

class Dog: Animal {
  override func speak() {
    super.speak()
    print("\(name) barks")
  }
}

// Prevent subclassing
final class Singleton {
  static let shared = Singleton()
  private init() {}
}
Computed properties & observers
struct Circle {
  var radius: Double
  var area: Double { .pi * radius * radius }   // computed (read-only)
  var diameter: Double {                         // computed (read-write)
    get { radius * 2 }
    set { radius = newValue / 2 }
  }
}

class Model {
  var count: Int = 0 {
    willSet { print("will change to \(newValue)") }
    didSet  { print("changed from \(oldValue)") }
  }
}
📋 Protocols
Protocol basics
protocol Drawable {
  var color: String { get }
  func draw()
  func resize(by factor: Double) mutating
}

// Default implementation (extension)
extension Drawable {
  func draw() { print("Drawing in \(color)") }
}

// Protocol composition
typealias DrawableIdentifiable = Drawable & Identifiable

func render(_ item: some Drawable) { item.draw() }

// Protocol inheritance
protocol AnimatableDrawable: Drawable {
  func animate(duration: Double)
}
Codable protocol
struct User: Codable {
  let id: Int
  let name: String
  let email: String?

  // Custom keys
  enum CodingKeys: String, CodingKey {
    case id, name
    case email = "user_email"
  }
}
🔣 Generics
Generic functions & types
// Generic function
func swap<T>(_ a: inout T, _ b: inout T) {
  let temp = a; a = b; b = temp
}

// Generic struct with constraint
struct Stack<T> {
  private var items: [T] = []
  mutating func push(_ item: T) { items.append(item) }
  mutating func pop() -> T? { items.popLast() }
  var top: T? { items.last }
}

// Where clause
func printIfEqual<T: Equatable>(_ a: T, _ b: T) {
  if a == b { print("Equal: \(a)") }
}

// some / any (Swift 5.7+)
func makeShape() -> some Shape { Circle() }       // opaque type
func render(_ shape: any Shape) { shape.draw() }   // existential
⏳ Async / Await
Async functions
func fetchUser(id: String) async throws -> User {
  let url = URL(string: "https://api.example.com/users/\(id)")!
  let (data, _) = try await URLSession.shared.data(from: url)
  return try JSONDecoder().decode(User.self, from: data)
}

// Call
Task {
  do {
    let user = try await fetchUser(id: "1")
    print(user.name)
  } catch { print(error) }
}
Parallel async (async let)
// Run in parallel — both start immediately
async let user  = fetchUser(id: "1")
async let posts = fetchPosts(userId: "1")

// Await both
let (u, p) = try await (user, posts)

// withTaskGroup
await withTaskGroup(of: User.self) { group in
  for id in ids {
    group.addTask { try await fetchUser(id: id) }
  }
  for await user in group { results.append(user) }
}
Actor (thread safety)
actor UserCache {
  private var cache: [String: User] = [:]

  func get(_ id: String) -> User? { cache[id] }

  func set(_ user: User, for id: String) {
    cache[id] = user
  }
}

let cache = UserCache()
await cache.set(user, for: user.id)
let cached = await cache.get("1")
🔗 Combine
Publishers & subscribers
import Combine

// Just (single value)
let publisher = Just(42)

// Subject
let subject = PassthroughSubject<Int, Never>()
let currentVal = CurrentValueSubject<Int, Never>(0)

// Subscribe
var cancellables = Set<AnyCancellable>()

subject
  .filter { $0 > 0 }
  .map { "Value: \($0)" }
  .receive(on: DispatchQueue.main)
  .sink { print($0) }
  .store(in: &cancellables)

subject.send(42)

// From Future (async bridge)
Future<User, Error> { promise in
  Task { try await promise(.success(fetchUser(id: "1"))) }
}
.sink(
  receiveCompletion: { _ in },
  receiveValue: { print($0) }
)
.store(in: &cancellables)
🔄 Codable / JSON
Encode & Decode JSON
let encoder = JSONEncoder()
encoder.keyEncodingStrategy    = .convertToSnakeCase
encoder.dateEncodingStrategy   = .iso8601
encoder.outputFormatting       = [.prettyPrinted, .sortedKeys]

let data = try encoder.encode(user)
let json = String(data: data, encoding: .utf8)!

let decoder = JSONDecoder()
decoder.keyDecodingStrategy  = .convertFromSnakeCase
decoder.dateDecodingStrategy = .iso8601

let user = try decoder.decode(User.self, from: data)