Nested Callbacks

ID

swift.nested_callbacks

Severity

info

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Complexity

Language

Swift

Tags

async, complexity

Description

Reports a callback closure whose nesting depth exceeds a configurable threshold. A "callback" here is a closure passed as an argument to a function call (including Swift’s trailing-closure syntax).

Configuration

  • maxNesting (default 5) — callback nesting depths strictly greater than this value are flagged.

Rationale

Deep callback chains — "callback hell" — are hard to read. Each level shifts the indentation and pulls the next operation away from the previous one, so the linear order of work disappears under the brace structure. Error handling becomes scattered, early returns are impossible, and defer no longer captures the natural lifetime of the operation. The classic refactor is async/await, which restores the linear shape; for event-style APIs, extracting named helper functions usually relieves the nesting too.

Notes

  • Only the inner-most offending closure is flagged so the issue count tracks refactorable spots, not the depth of the chain.

  • Closures that are not in an argument position (e.g. a closure stored in a variable) are not considered callbacks.

Remediation

// Callback pyramid.
fetch(url) { res in
    parse(res) { data in
        transform(data) { out in
            persist(out) { id in
                notify(id) { ... }
            }
        }
    }
}

// Linear with async/await.
let res = try await fetch(url)
let data = try await parse(res)
let out  = try await transform(data)
let id   = try await persist(out)
try await notify(id)