Skip to content
Back to skills

Loom Swift

ASecurity

Swift language expertise for idiomatic, production-quality code.

  • 56 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 1, 2026
ai-agentsrustgoswiftshellbashexpressawstestinggitapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 1, 2026

npx -y skills add cosmix/loom --skill loom-swift --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Loom Swift?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Loom Swift
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/cosmix-loom-swift/badge)](https://www.skillsdirectory.com/skills/cosmix-loom-swift)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: loom-swift
description: Swift language expertise for idiomatic, production-quality code.
triggers:
  - swift
  - swiftpm
  - spm
  - Package.swift
  - xcode
  - xcodebuild
  - xctest
  - swift testing
  - swift-format
  - swiftlint
  - swiftui
  - uikit
  - vapor
  - sendable
  - actor
  - mainactor
  - async let
  - taskgroup
  - codable
  - ios
  - macos
---

# Swift Language Expertise

## Overview

Idiomatic, production-grade Swift 6: SwiftPM packages, value semantics, optionals, protocol-oriented generics, and structured concurrency under strict data-race checking. Assumes the reader knows the syntax. The value is in what is easy to get wrong: protocol-extension dispatch, actor reentrancy, `Sendable` escape hatches, continuation misuse, `Codable` defaults, and two test frameworks that share one `swift test` command.

## Tooling

SwiftPM is the build tool and package manager. Xcode projects (`.xcodeproj`) build with `xcodebuild`; keep libraries in a SwiftPM package even when an app wraps them, so they build and test on Linux and in CI without a simulator.

| Task | Command |
| --- | --- |
| New package | `swift package init --type library` (or `--type executable`) |
| Add a dependency | `swift package add-dependency https://github.com/apple/swift-argument-parser --from 1.5.0` (6.0+) |
| Wire it to a target | `swift package add-target-dependency ArgumentParser spool-cli --package swift-argument-parser` |
| Resolve / update | `swift package resolve` / `swift package update` (rewrites `Package.resolved`) |
| Build with tests | `swift build --build-tests` |
| Test | `swift test` (`--parallel` for XCTest; Swift Testing runs tests in parallel by default) |
| List test ids | `swift test list` |
| Release build | `swift build -c release` (whole-module optimization) |
| Format | `swift format --in-place --recursive Sources Tests` (swift-format ships with the 6.0 toolchain) |
| Lint | `swift format lint --strict --recursive Sources Tests`; `swiftlint lint --strict` where `.swiftlint.yml` exists |

```swift
// swift-tools-version: 6.0
// The tools version line selects the manifest API AND the Swift 6 language mode for every target.
import PackageDescription

let package = Package(
    name: "Spool",
    platforms: [.macOS(.v14), .iOS(.v17)],
    products: [.library(name: "Spool", targets: ["Spool"])],
    dependencies: [
        .package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"),
    ],
    targets: [
        .target(name: "Spool"),
        .executableTarget(name: "spool-cli", dependencies: [
            "Spool",
            .product(name: "ArgumentParser", package: "swift-argument-parser"),
        ]),
        .testTarget(name: "SpoolTests", dependencies: ["Spool"]),
    ]
)
```

- Commit `Package.resolved` for applications and executables. Libraries may leave it out: consumers resolve their own graph.
- Migrating an older target: `swiftSettings: [.swiftLanguageMode(.v5), .enableUpcomingFeature("StrictConcurrency")]` keeps Swift 5 mode while surfacing the data-race diagnostics as warnings; remove both once they are fixed.
- Keep executables thin. Logic lives in a library target so tests `@testable import` it.

The canonical gate:

```bash
swift format lint --strict --recursive Sources Tests
swift build --build-tests -Xswiftc -warnings-as-errors
swift test --parallel
```

If `-warnings-as-errors` trips on a dependency's code, drop the flag and fail CI on `warning:` lines under your own `Sources/` and `Tests/` instead.

## Value Types and Copy-on-Write

- Default to `struct` and `enum`. Use `class` when identity or shared mutable state is the point (a connection, a cache, a UIKit object). A struct copy mutates independently, which removes aliasing bugs and makes `Sendable` conformance free when every stored property is `Sendable`.
- A struct holding a class reference copies the reference. Both copies share the object; value semantics stop at that field.
- `Array`, `Dictionary`, `Set` and `String` are copy-on-write: a copy is O(1) and the first mutation of a shared buffer copies it. A struct that wraps its own class storage must implement CoW itself.
- Exclusivity: overlapping `inout` access to one variable is a compile error when the compiler can see it and a runtime trap ("Simultaneous accesses") when it cannot.

```swift
final class Storage { var bytes: [UInt8] = [] }

struct Buffer {
    private var storage = Storage()

    mutating func append(_ byte: UInt8) {
        if !isKnownUniquelyReferenced(&storage) {   // shared: copy before writing
            let copy = Storage()
            copy.bytes = storage.bytes
            storage = copy
        }
        storage.bytes.append(byte)
    }
}

var counts = [1, 2, 3]
swap(&counts[0], &counts[1])   // error: overlapping accesses to 'counts'
counts.swapAt(0, 1)            // the API for this case
```

## Optionals and Errors

- Unwrap with `if let value`, `guard let value else { return }` (5.7 shorthand), `??` and optional chaining. `guard` keeps the success path unindented.
- `!`, `try!` and `as!` assert a fact the program itself guarantees. Data from outside the program (environment, files, network, user input) is never such a fact.
- Model failures as an `enum` conforming to `Error` with associated values. `try?` discards the reason; use it only where the reason does not matter.
- Typed throws (6.0): `throws(SpoolError)` fits module-internal code and closed error sets. Keep untyped `throws` on public API: a typed error set is part of the signature and cannot grow without breaking callers.
- `precondition` and `fatalError` survive `-O`; `assert` is compiled out of release builds. Never validate input with `assert`.

```swift
enum ConfigError: Error, Equatable {
    case missing(key: String)
    case invalid(key: String, value: String)
}

func port(from env: [String: String]) throws(ConfigError) -> Int {
    guard let raw = env["PORT"] else { throw .missing(key: "PORT") }
    guard let value = Int(raw), (1...65_535).contains(value) else {
        throw .invalid(key: "PORT", value: raw)
    }
    return value
}

do {
    let p = try port(from: ProcessInfo.processInfo.environment)
    print("listening on \(p)")
} catch ConfigError.missing(let key) {
    print("set \(key)")
} catch {
    print("bad config: \(error)")
}
```

## Protocols and Generics

- `some P` is one concrete type chosen at compile time: static dispatch, specialization, no boxing. `any P` is an existential box with dynamic dispatch and possible heap allocation. Default to `some P` or a generic parameter; use `any P` for heterogeneous storage.
- Primary associated types constrain both forms: `some Collection<Int>`, `any AsyncSequence<Event, Never>`.
- Conditional conformance: `extension Array: Drawable where Element: Drawable {}`.
- Conforming a type you do not own to a protocol you do not own warns in Swift 6; mark it `extension URL: @retroactive Identifiable` only when you accept that the owner may add the same conformance later.
- ⚠ Only protocol **requirements** dispatch dynamically. A method defined only in a protocol extension is picked by the static type, so a conforming type's same-named method is ignored through `any P` or a generic `T: P`.

```swift
protocol Greeter {
    func greet() -> String                  // requirement: dynamic dispatch
}

extension Greeter {
    func greet() -> String { "hello" }
    func farewell() -> String { "bye" }     // extension only: static dispatch
}

struct Loud: Greeter {
    func greet() -> String { "HELLO" }
    func farewell() -> String { "BYE" }
}

let g: any Greeter = Loud()
g.greet()      // "HELLO"
g.farewell()   // "bye": the extension method, chosen at compile time
```

## Structured Concurrency

- `async let` runs a fixed number of children concurrently; `withThrowingTaskGroup` runs a dynamic number. When the scope exits by error, remaining children are cancelled and awaited.
- Cancellation is cooperative. Check `try Task.checkCancellation()` in loops; `Task.sleep` throws `CancellationError`.
- An unstructured `Task { }` inherits the caller's actor and priority but no cancellation. `Task.detached` inherits nothing. Keep the handle of every unstructured task and cancel it when its owner goes away.
- Actors serialize access to their state, and they are **reentrant**: at every `await` other calls may run and change that state. Re-check invariants after each suspension.
- `@MainActor` isolates UI state and view models.
- `Sendable`: structs and enums whose members are `Sendable` conform implicitly (inside the module). A class conforms when it is `final` with only `let` `Sendable` properties, or when a lock guards its state and it is marked `@unchecked Sendable` with a comment naming the lock. `Mutex` from the `Synchronization` module (6.0, macOS 15 / iOS 18) is that lock.
- Swift 6 language mode turns data-race diagnostics into errors. `@preconcurrency import LegacyKit` quiets diagnostics from a module that has not adopted `Sendable` yet.
- Swift 6.2 adds `.defaultIsolation(MainActor.self)` per target and the `NonisolatedNonsendingByDefault` upcoming feature, under which a nonisolated `async` function runs on the caller's actor unless marked `@concurrent`. Read the target's `swiftSettings` before reasoning about where an async function runs.

```swift
func loadDashboard(user: User.ID) async throws -> Dashboard {
    async let profile = api.profile(user)      // both requests start here
    async let orders = api.orders(user)
    return try await Dashboard(profile: profile, orders: orders)
}

func fetchAll(_ ids: [Item.ID]) async throws -> [Item] {
    try await withThrowingTaskGroup(of: Item.self) { group in
        for id in ids {
            group.addTask { try await api.item(id) }
        }
        var items: [Item] = []
        for try await item in group { items.append(item) }
        return items                             // a child's error cancels the rest
    }
}

actor DownloadCache {
    private var cache: [URL: Data] = [:]
    private var inFlight: [URL: Task<Data, Error>] = [:]

    func data(for url: URL) async throws -> Data {
        if let hit = cache[url] { return hit }
        if let running = inFlight[url] { return try await running.value }
        let task = Task { try await download(url) }
        inFlight[url] = task                     // record before suspending
        defer { inFlight[url] = nil }
        let data = try await task.value          // other callers run during this await
        cache[url] = data
        return data
    }
}
```

Bridging callback APIs: a checked continuation must be resumed exactly once on every path. Resuming twice traps; never resuming leaks the task and logs `SWIFT TASK CONTINUATION MISUSE`.

```swift
func fetch(_ url: URL) async throws -> Data {
    try await withCheckedThrowingContinuation { continuation in
        legacyClient.fetch(url) { result in
            continuation.resume(with: result)    // Result<Data, Error>: one resume on every path
        }
    }
}
```

## Modules and Access Control

- Each target is a module. `internal` (the default) is module-wide; `public` exposes API; `open` also allows subclassing and overriding outside the module; `package` (5.9) spans the modules of one package; `fileprivate` and `private` narrow further.
- Tests reach `internal` symbols with `@testable import Spool`. Do not widen access for a test.
- Resources: `resources: [.process("Fixtures")]` on the target, read through `Bundle.module`.
- `@unknown default` in a `switch` over an enum from another module (SDK enums, resilient libraries) keeps the code compiling when the enum gains a case, and warns so you handle it.

## SwiftUI Essentials

- Views are values that SwiftUI recreates often. Keep `body` cheap and free of side effects.
- State ownership: `@State` for view-owned values and for an `@Observable` model the view creates; `@Binding` for a child that writes its parent's value; `@Bindable` for bindings into an `@Observable` model; `@Environment` for injected shared objects. `@StateObject` and `@ObservedObject` remain for `ObservableObject` before iOS 17.
- `.task { }` runs async work tied to the view's lifetime and cancels it when the view disappears; `.task(id:)` restarts when the id changes. Prefer it to `onAppear { Task { } }`, which never cancels.

```swift
import Observation
import SwiftUI

@MainActor
@Observable
final class SpoolModel {
    var entries: [String] = []
    var failure: String?

    func reload(client: SpoolClient) async {
        do { entries = try await client.list() } catch { failure = error.localizedDescription }
    }
}

struct SpoolView: View {
    let client: SpoolClient
    @State private var model = SpoolModel()

    var body: some View {
        List(model.entries, id: \.self) { Text($0) }
            .overlay { if let failure = model.failure { Text(failure) } }
            .task { await model.reload(client: client) }   // cancelled when the view goes away
    }
}
```

## Testing

Two frameworks run under one `swift test`:

| | XCTest | Swift Testing (6.0 toolchain) |
| --- | --- | --- |
| Declare | `final class FooTests: XCTestCase` with `func testX()` | `@Test func x()`, optionally in a `@Suite` type |
| Assert | `XCTAssertEqual`, `XCTAssertThrowsError`, `XCTUnwrap` | `#expect(a == b)`, `#expect(throws:)`, `try #require(x)` |
| Setup | `setUpWithError` / `tearDownWithError`, `addTeardownBlock` | the suite's `init` (a fresh instance per test), `deinit` on a class suite |
| Parameterize | loop inside one test | `@Test(arguments: [...])`, one result per argument |
| Parallelism | serial unless `--parallel` | parallel by default; `.serialized` trait to opt out |

```swift
import XCTest
@testable import Spool

final class SpoolWriterTests: XCTestCase {
    private var dir: URL!

    override func setUpWithError() throws {
        dir = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
        try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
    }

    override func tearDownWithError() throws {
        try FileManager.default.removeItem(at: dir)
    }

    func testAppendsOneRecord() throws {
        let writer = try SpoolWriter(path: dir.appendingPathComponent("spool").path)
        try writer.append(Data("x".utf8))
        let segment = try XCTUnwrap(writer.segments.first)
        XCTAssertEqual(segment.size, 1)
    }

    func testDrainsAsync() async throws {
        let writer = try SpoolWriter(path: dir.appendingPathComponent("spool").path)
        let drained = try await writer.drain()
        XCTAssertEqual(drained, 0)
    }
}
```

```swift
import Foundation
import Testing
@testable import Spool

@Suite struct RotationTests {
    let dir: URL

    init() throws {
        dir = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
        try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
    }

    @Test(arguments: [1, 64, 4096])
    func rotatesAtLimit(limit: Int) throws {
        let spool = try Spool(directory: dir, maxBytes: limit)
        try spool.append(Data(repeating: 0, count: limit + 1))
        #expect(spool.segments.count == 2)
    }

    @Test func unknownSegmentThrows() throws {
        let spool = try Spool(directory: dir, maxBytes: 10)
        #expect(throws: SpoolError.self) { try spool.segment(named: "absent") }
    }
}
```

- Async XCTest: `func testX() async throws`; wait for expectations with `await fulfillment(of: [exp], timeout: 1)`. `wait(for:)` is marked `noasync`: it blocks the thread an async test runs on.
- Inject clocks (`any Clock<Duration>`) and file-system roots instead of sleeping or touching real paths.
- Run one test: `swift test --filter 'SpoolTests.SpoolWriterTests/testAppendsOneRecord'`; skip with `--skip`.

## Loom Test Runner Adapter

**Adapter.** `swift-test`. A directory containing `Package.swift` is a `swift` package, and loom's detection always picks `swift-test` for it. `loom project detect` prints the kind, runner and skill per package. An Xcode-only project without `Package.swift` is not detected as `swift`.

**Single-test command.** Loom runs each contract with the package directory as the working directory:

```bash
swift test --filter '{test}'
```

**The `test` field.** `Module.Class/testMethod`, where `Module` is the test target's module name. `swift test list` prints ids in this form. Example: `SpoolTests.SpoolWriterContractTests/testRejectsSymlinkedSpool`.

**No-match behaviour.** Documented: swift was not installed on the host that captured runner fixtures, so loom's parser for `swift-test` was written from the runner's documented output. Do not rely on the exit code. Loom reads the XCTest summary `Executed N tests, with F failures`; `Executed 0 tests` means nothing was selected, so a contract test whose name does not match fails the freeze. A plan criterion that runs `swift test --filter ...` and executes zero tests fails the same way (`selected zero tests (swift-test)`).

**Writing contract tests.**

- SwiftPM compiles every `.swift` file under `Tests/<TestTarget>/` into that test target. Put a contract in the existing test target, in a file named for its subject: `Tests/SpoolTests/SpoolWriterContractTests.swift`.
- Write contract tests as XCTest methods. The adapter's `test` format and its parser are XCTest's; a Swift Testing `@Test` function prints a separate summary that the adapter does not read, so a filter that selects only Swift Testing tests can read as zero tests executed.
- `--filter` is an unanchored regular expression. `testRejectsSymlink` also selects `testRejectsSymlinkedSpool`, so choose a method name that no other test id in the package contains.
- Any other file the contract session changes (a shared fixture, a new test target in `Package.swift`) must match a `harness` glob, or the freeze rejects it.
- Resolve and build once (`swift build --build-tests`) before writing contracts, so the freeze run compiles only your test target instead of fetching and building dependencies inside its 300-second limit. `.build/` must be in `.gitignore` (`swift package init` writes it); the freeze treats every other untracked path as a change.
- Loom cannot batch-select Swift tests by file, so impact-selected tests are skipped with a note for Swift packages; the full suite still runs in integration-verify.

```swift
import Foundation
import XCTest
@testable import Spool

final class SpoolWriterContractTests: XCTestCase {
    func testRejectsSymlinkedSpool() throws {
        let dir = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
        try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
        addTeardownBlock { try? FileManager.default.removeItem(at: dir) }

        let target = dir.appendingPathComponent("target")
        let link = dir.appendingPathComponent("spool")
        try Data().write(to: target)
        try FileManager.default.createSymbolicLink(at: link, withDestinationURL: target)

        XCTAssertThrowsError(try SpoolWriter(path: link.path)) { error in
            XCTAssertEqual(error as? SpoolError, .symlinked(path: link.path))
        }
        XCTAssertEqual(try Data(contentsOf: target), Data())
    }
}
```

```yaml
contracts:
  - id: rejects-symlinked-spool
    file: Tests/SpoolTests/SpoolWriterContractTests.swift
    test: SpoolTests.SpoolWriterContractTests/testRejectsSymlinkedSpool
    scenario: the spool path is a symlink to an empty file in a fresh temporary directory
    rejects: a SpoolWriter that opens the path with default flags, follows the link and writes through it
```

**Build failures.** Swift is compiled: a contract test that does not compile yet (it calls an API the stage has not written) counts as red at freeze time; compiler `error:` lines mark the run as a build failure. One file that fails to compile fails the whole test target, so every test in that target stays red until the implementation compiles.

## Anti-Patterns

```swift
// Force unwrap on data from outside the program
let port = Int(env["PORT"]!)!                                   // BAD: crashes on a missing or bad value
guard let raw = env["PORT"], let port = Int(raw) else {         // GOOD
    throw ConfigError.missing(key: "PORT")
}

// Fire-and-forget task: its error vanishes and nothing can cancel it
Task { try await sync() }                                       // BAD
syncTask = Task { try await sync() }                            // GOOD: stored, cancelled in deinit/onDisappear

// Blocking a cooperative-pool thread to wait for async work
let done = DispatchSemaphore(value: 0)                          // BAD: can starve the pool and deadlock
Task { await work(); done.signal() }
done.wait()

// Retain cycle: self owns the closure, the closure owns self
timer.handler = { self.tick() }                                 // BAD
timer.handler = { [weak self] in self?.tick() }                 // GOOD
```

Quick swaps: `@unchecked Sendable` to silence a diagnostic → fix the type or guard it with a lock and say which; `DispatchQueue.main.async` inside async code → `@MainActor` isolation; `class` with no identity → `struct`; implicitly unwrapped optionals outside XCTest fixtures and IB outlets → a non-optional set in `init`; `catch { }` → handle, rethrow, or log with context; stringly-typed errors → an `Error` enum.

## Expert Practices

### Language Gotchas

- **`String` is a collection of grapheme clusters.** `count` is O(n), `"e\u{301}".count == 1` while `.utf8.count == 3`, and subscripts take a `String.Index` from the same string. Work on `.utf8` for byte protocols.
- **Integer overflow traps in release builds too.** `Int.max + 1` crashes. Use `&+`/`&*` for intended wrapping and `addingReportingOverflow` on untrusted sizes. `Int(someDouble)` traps on NaN, infinity and out-of-range values; use `Int(exactly:)`.
- **`lazy var` is not thread-safe.** Two threads can both run the initializer. A `static let` is lazily initialized exactly once, safely.
- **`defer` runs at scope exit in reverse order,** once per loop iteration when declared in a loop body.
- **`weak` becomes `nil`; `unowned` crashes** when the object is gone. Use `unowned` only when the lifetime relation is guaranteed.
- **A custom `==` needs a matching `hash(into:)`.** Synthesized conformances cover every stored property; override both or neither.

### Concurrency Gotchas

- **Global and static mutable state is an error in Swift 6 mode.** Make it a `let`, move it into an actor, or guard it with a `Mutex`. `nonisolated(unsafe) var` is a last resort that needs a comment explaining why no race is possible.
- **`MainActor.assumeIsolated { }`** asserts at runtime that a callback runs on the main thread; it traps otherwise. Prefer making the callback API `@MainActor`.
- **`AsyncStream` buffers without bound by default.** Pass `bufferingPolicy: .bufferingNewest(n)` for fast producers, and release resources in `continuation.onTermination`.
- **`Task.detached` is rarely right.** It drops priority, task-local values and actor context; a `nonisolated` async function or a `@concurrent` one (6.2) usually expresses the intent.
- **Actor-isolated state read before an `await` may be stale after it.** Write the "check then act" sequence without a suspension point in between, or record the in-flight work (see `DownloadCache` above).

### Codable

- **`JSONDecoder`'s default date strategy is `.deferredToDate`:** a `Double` of seconds since 2001-01-01. ISO 8601 strings need `.iso8601`, and that strategy rejects fractional seconds; decode those with `.custom` and `Date.ISO8601FormatStyle(includingFractionalSeconds: true)`.
- **Synthesized decoding ignores property defaults.** `var retries = 3` still throws `keyNotFound` when the key is absent; a `let` with an initial value is never decoded at all (the compiler warns). Make the field optional or write `init(from:)` with `decodeIfPresent(...) ?? 3`.
- **An unknown raw value throws `dataCorrupted`.** For enums the server may extend, decode through a type with an `unknown(String)` case.
- `keyDecodingStrategy = .convertFromSnakeCase` saves hand-written `CodingKeys` for snake-case payloads.

### Performance

- `final` classes and `private` members let the compiler devirtualize calls; release builds use whole-module optimization.
- Generic and `some` code specializes; `any` boxes values and dispatches through witness tables. Keep `any` out of hot loops.
- `reserveCapacity` before appending a known count; iterate `.utf8` or `.unicodeScalars` for byte-level parsing.
- `@inlinable` lets client modules specialize a generic function, and publishes its body as part of the module's interface. Use it on small, stable functions.
- Profile before tuning: Instruments on Apple platforms, `perf` on Linux, the package-benchmark plugin for regression tracking.

### Security

- **Open without following links.** A symlink check followed by a separate `open` races with an attacker swapping the path. Pass `O_NOFOLLOW` to `open(2)`; it fails with `ELOOP` on a symlink.

```swift
import Foundation   // re-exports Darwin or Glibc

func openSpool(atPath path: String) throws(SpoolError) -> Int32 {
    let fd = open(path, O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW, 0o600)
    guard fd >= 0 else {
        if errno == ELOOP { throw .symlinked(path: path) }
        throw .notWritable(path: path)
    }
    return fd
}
```

- **Processes:** set `Process.executableURL` and pass an `arguments` array. Never build a `/bin/sh -c` string from input.
- **Randomness and crypto:** `SystemRandomNumberGenerator` (the default for `Int.random(in:)`) draws from the platform's secure source. Use CryptoKit or swift-crypto for hashes, HMAC and AEAD, and verify MACs with `HMAC<SHA256>.isValidAuthenticationCode(_:authenticating:using:)`, which compares in constant time.
- **Secrets** belong in the Keychain on Apple platforms. `UserDefaults` is a plain property list on disk.
- **Format strings:** `String(format:)` and `NSPredicate(format:)` with user-controlled format text are injection points. Keep the format literal and pass values as arguments.
- **TLS:** never answer a `URLSession` authentication challenge by trusting every certificate; pin with the server trust APIs when the threat model needs it.

## Verification Checklists

**Before marking Swift work done:**

- [ ] `swift format lint --strict` clean (or SwiftLint where the project configures it)
- [ ] `swift build --build-tests` with zero warnings in your own targets
- [ ] `swift test` green; new behaviour has tests, parameterized where inputs vary
- [ ] No `!`, `try!` or `as!` on data from outside the program; no `assert` used for validation
- [ ] Public API uses untyped `throws`; typed throws only on closed, internal error sets
- [ ] Dependencies added with `swift package add-dependency`; `Package.resolved` committed for applications
- [ ] `Codable` models tested against real payloads (dates, missing keys, unknown enum values)
- [ ] No shell strings built from input; secrets not stored in `UserDefaults`

**Concurrency review:**

- [ ] Swift 6 language mode, or strict concurrency enabled on targets still in Swift 5 mode
- [ ] Every `@unchecked Sendable` and `nonisolated(unsafe)` names the lock or invariant that makes it safe
- [ ] Every unstructured `Task` has a stored handle and a cancellation path
- [ ] Actor methods re-check state after each `await`; no check-then-act across a suspension
- [ ] Continuations resume exactly once on every path; no semaphores waiting on async work

**Loom contracts:**

- [ ] Contract tests are XCTest methods in the package's test target
- [ ] Each `test` value is the `Module.Class/testMethod` id from `swift test list`, and no other test id contains it
- [ ] Dependencies resolved and built before the freeze; each contract fails now, by assertion or by not compiling

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…