Overview › Swift Concurrency

Swift Concurrency

async/await adopted in newer modules; legacy completion handlers + DispatchQueue dominate.

2 findings in this category · iOS
72
SCORE

Summary

The project supports Swift Concurrency (async/await) — newer SPM packages adopt it — but legacy code relies heavily on Grand Central Dispatch and completion handlers. 40+ DispatchQueue.main.asyncAfter calls observed without DispatchWorkItem for cancellation.

Findings

PASS

async/await adopted in newer features

Newer SPM packages use async functions and Task. CostcoNetworkClient supports async API alongside completion handlers.
HIGH

asyncAfter without cancellation

40+ instances of DispatchQueue.main.asyncAfter with closures that capture self strongly. Stale callbacks fire after view dismissal and can crash or trigger duplicated state changes.
Recommendation: Use DispatchWorkItem stored on the view controller; call cancel() in viewWillDisappear. Or replace with Task + Task.cancel.
HIGH

Strong-self capture in escaping closures

Many completion-handler closures don't use [weak self] or [unowned self]. Combined with long-lived references (NotificationCenter, Timer), retain cycles are likely.
Recommendation: SwiftLint rule for closure capture; require [weak self] in escaping closures stored on long-lived objects.
MEDIUM

DispatchQueue.main.sync deadlock risk

Calling main.sync from the main thread deadlocks the app. Audit any main.sync usage.
Recommendation: Replace with main.async or restructure caller to be on a background queue.
LOW

Combine + async/await dual world

Some code uses Combine publishers, others use AsyncSequence. Pick a primary pattern per feature to avoid bridging boilerplate.
Recommendation: Document a default — likely async/await + AsyncSequence for new code; let Combine remain only where deeply integrated.

Findings in this category

2 shown
Costco iOS · Code Review Report · Generated 2026-05-07 · 88 machine-curated findings