Skip to content
Back to skills

353 Concurrency 6d1d0bb3

ASecurity

```swift // BAD - sequential awaits on independent operations let user = await fetchUser() let avatar = await fetchAvatar(for: user.id) // Waits unnecessarily let prefs = await fetchPreferences(for: user.id) // Waits unnecessarily

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
code-qualitygoswiftdatabase

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 353-concurrency_6d1d0bb3 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 353 Concurrency 6d1d0bb3?

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

Security grade badge for 353 Concurrency 6d1d0bb3
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-353-concurrency-6d1d0bb3/badge)](https://www.skillsdirectory.com/skills/tools-only-353-concurrency-6d1d0bb3)

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

SKILL.md
# Swift Concurrency

## Critical Anti-Patterns

### 1. Sequential Execution When Concurrent Is Possible

```swift
// BAD - sequential awaits on independent operations
let user = await fetchUser()
let avatar = await fetchAvatar(for: user.id)      // Waits unnecessarily
let prefs = await fetchPreferences(for: user.id)  // Waits unnecessarily

// GOOD - async let for independent operations
let user = await fetchUser()
async let avatar = fetchAvatar(for: user.id)
async let prefs = fetchPreferences(for: user.id)
return Profile(user: user, avatar: try await avatar, prefs: try await prefs)
```

### 2. Memory Leaks from Task Self-Capture

```swift
// BAD - self captured indefinitely in async sequence
Task {
    for await notification in stream {
        handleNotification(notification)  // implicit self
    }
}

// GOOD - weak self with guard inside the loop
Task { [weak self] in
    for await notification in stream {
        guard let self else { return }
        self.handleNotification(notification)
    }
}
```

### 3. Actor Reentrancy Bugs

```swift
// BAD - state check before await, mutation after
actor BankAccount {
    var balance: Double = 1000
    func withdraw(_ amount: Double) async -> Bool {
        guard balance >= amount else { return false }
        await recordTransaction(amount)  // state can change here!
        balance -= amount  // may go negative
        return true
    }
}

// GOOD - mutate state before await
func withdraw(_ amount: Double) async -> Bool {
    guard balance >= amount else { return false }
    balance -= amount  // safe - done before suspension
    await recordTransaction(amount)
    return true
}
```

### 4. Stateless Actors

```swift
// BAD - actor with nothing to protect
actor NetworkService {
    func fetchData(from url: URL) async throws -> Data {
        try await URLSession.shared.data(from: url).0
    }
}

// GOOD - use enum or struct for stateless operations
enum NetworkService {
    static func fetchData(from url: URL) async throws -> Data {
        try await URLSession.shared.data(from: url).0
    }
}
```

### 5. Ignoring Task Cancellation

```swift
// BAD - long loop ignores cancellation
for item in items {
    await process(item)
}

// GOOD - check cancellation
for item in items {
    try Task.checkCancellation()
    await process(item)
}
```

### 6. Non-Sendable Types Across Actors

```swift
// BAD - mutable class crossing boundaries
class Session { var token: String? }

// GOOD - immutable struct
struct Session: Sendable { let token: String }

// GOOD - @unchecked with actual lock
final class Session: @unchecked Sendable {
    private let lock = NSLock()
    private var _token: String?
    var token: String? {
        get { lock.withLock { _token } }
        set { lock.withLock { _token = newValue } }
    }
}
```

### 7. Errors Silently Ignored in Tasks

```swift
// BAD - error lost
Task { try await database.save(data) }

// GOOD - handle explicitly
Task {
    do { try await database.save(data) }
    catch { logger.error("Save failed: \(error)") }
}
```

## Best Practices

- **Use `async let`** for 2-3 independent operations
- **Use `TaskGroup`** for dynamic number of concurrent tasks with result aggregation
- **Apply `@MainActor` at type level** for ViewModels, not scattered `MainActor.run`
- **Use `.task` modifier** in SwiftUI instead of `Task` in `onAppear`
- **Use `nonisolated`** for pure functions in @MainActor types
- **Limit TaskGroup concurrency** with iterator pattern for large workloads

## Review Questions

1. Are independent async operations running concurrently?
2. Could actor state change across suspension points (reentrancy)?
3. Is `@unchecked Sendable` backed by actual synchronization?
4. Are long-running Tasks checking `Task.isCancelled`?
5. Are errors in Task closures being handled or silently lost?

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…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.