# Swift Patterns

> When to activate: general Swift code, value types, enums, pattern matching, optionals, result types, property wrappers

- Skill: `mattakushi432/swift-patterns` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mattakushi432/swift-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mattakushi432/swift-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Mattakushi432 (https://skillmd.com/u/mattakushi432)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mattakushi432/swift-patterns

---


# Swift Patterns

## Value Types First

Prefer structs and enums over classes unless you need reference semantics.

```swift
// Good — value type, copyable, predictable
struct Point {
    var x: Double
    var y: Double

    func distance(to other: Point) -> Double {
        sqrt(pow(x - other.x, 2) + pow(y - other.y, 2))
    }
}

// Only use class when you need shared mutable state or ObjC interop
final class UserSession {
    private(set) var token: String
    init(token: String) { self.token = token }
}
```

## Enums with Associated Values

Model domain states exhaustively — never use stringly-typed sentinels.

```swift
enum AuthState {
    case unauthenticated
    case authenticating
    case authenticated(User)
    case failed(AuthError)
}

func handle(_ state: AuthState) {
    switch state {
    case .unauthenticated:       showLogin()
    case .authenticating:        showSpinner()
    case .authenticated(let u):  showDashboard(user: u)
    case .failed(let e):         showError(e)
    }
}
```

## Optionals

```swift
// Use guard for early exit
func process(input: String?) -> String {
    guard let value = input, !value.isEmpty else { return "" }
    return value.uppercased()
}

// map/flatMap on Optional avoids repeated unwrapping
let length = name?.count
let trimmed = name?.trimmingCharacters(in: .whitespaces)

// Force unwrap only for known-safe static values
let url = URL(string: "https://api.example.com")!
```

## Result Type

```swift
enum NetworkError: Error {
    case invalidURL, timeout, serverError(Int), decodingFailed
}

func fetch<T: Decodable>(url: URL) async -> Result<T, NetworkError> {
    do {
        let (data, response) = try await URLSession.shared.data(from: url)
        guard let http = response as? HTTPURLResponse, http.statusCode == 200 else {
            return .failure(.serverError((response as? HTTPURLResponse)?.statusCode ?? 0))
        }
        return .success(try JSONDecoder().decode(T.self, from: data))
    } catch is DecodingError {
        return .failure(.decodingFailed)
    } catch {
        return .failure(.timeout)
    }
}
```

## Property Wrappers

```swift
@propertyWrapper
struct Clamped<T: Comparable> {
    private var value: T
    let range: ClosedRange<T>

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

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

struct Player {
    @Clamped(0...100) var health: Int = 100
    @Clamped(0...1)   var speed: Double = 0.5
}
```

## Pattern Matching

```swift
// if case let for single-case matching
if case .authenticated(let user) = authState {
    print("Logged in as \(user.name)")
}

// for-case in collections
let errors = results.compactMap {
    if case .failure(let e) = $0 { return e } else { return nil }
}

// switch with where clauses
switch response.statusCode {
case 200..<300:           handleSuccess(data)
case 400 where debug:     log("Bad request: \(response)")
case 400..<500:           handleClientError(response.statusCode)
case 500...:              handleServerError(response.statusCode)
default:                  break
}
```

## Common Anti-Patterns

- **Force unwrap `!`** in production — use `guard let` or `if let`
- **Classes for pure data** — structs are thread-safe by default
- **Stringly-typed state** — model with enums and associated values
- **Ignoring `Result`** — propagate errors; avoid sentinel `nil` returns
- **`@objc` everywhere** — annotate only what ObjC actually needs

