### Install Node.js using Homebrew Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/README.md If 'npx: command not found' error occurs, install Node.js using Homebrew. This is a prerequisite for using npx. ```bash brew install node ``` -------------------------------- ### Start Tasks Synchronously with Task.immediate Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/new-features.md Use Task.immediate to start a task that runs immediately on the current executor if possible, rather than being queued. This is useful for synchronous work before the first suspension point. ```swift print("Starting") Task { print("In Task") } Task.immediate { print("In Immediate Task") } print("Done") try await Task.sleep(for: .seconds(0.1)) ``` -------------------------------- ### Install Swift Concurrency Agent Skill for Claude Code Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/README.md Use these commands to add the Swift Concurrency Agent Skill marketplace and install the plugin for Claude Code. ```bash /plugin marketplace add twostraws/Swift-Concurrency-Agent-Skill /plugin install swift-concurrency-pro@swift-concurrency-agent-skill ``` -------------------------------- ### Install Swift Concurrency Agent Skill for Codex, Gemini, Cursor Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/README.md Use this command to add the Swift Concurrency Agent Skill for agents like Codex, Gemini, and Cursor. Ensure Node.js is installed. ```bash npx skills add https://github.com/twostraws/swift-concurrency-agent-skill --skill swift-concurrency-pro ``` -------------------------------- ### Limiting Concurrency with Task Groups in Swift Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/structured.md Manually limit the concurrency of task groups when eager launching of all child tasks is undesirable. This example starts an initial batch of tasks and then adds new tasks as existing ones complete, ensuring a maximum concurrency level. ```swift try await withThrowingTaskGroup { group in let maxConcurrent = 4 var iterator = urls.makeIterator() // Start initial batch for _ in 0..? func load() { loadTask = Task { await fetchData() } } } ``` ```swift func load() { loadTask?.cancel() loadTask = Task { await fetchData() } } deinit { loadTask?.cancel() } ``` -------------------------------- ### Manage Continuation Lifecycle Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/async-streams.md Ensure a continuation is finished exactly once. Use `onTermination` to handle cleanup if the producer might be deallocated before the stream finishes. ```swift let (stream, continuation) = AsyncStream.makeStream(of: Event.self) let monitor = NetworkMonitor() monitor.onEvent = { event in continuation.yield(event) } monitor.onComplete = { continuation.finish() } continuation.onTermination = { _ in monitor.stop() } ``` -------------------------------- ### Actor with In-Flight Task Handling Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/actors.md Implements a robust actor that prevents duplicate downloads for the same URL by tracking in-flight tasks. This ensures that only one download is initiated for a given URL while others wait for its completion. ```swift actor VideoCache { var items: [URL: Video] = [: ] var inFlight: [URL: Task] = [: ] func video(for url: URL) async throws -> Video { if let cached = items[url] { return cached } if let task = inFlight[url] { return try await task.value } let task = Task { try await downloadVideo(url) } inFlight[url] = task do { let video = try await task.value items[url] = video inFlight[url] = nil return video } catch { inFlight[url] = nil throw error } } } ``` -------------------------------- ### Using Isolated Parameter for Main Actor Execution Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/actors.md Demonstrates the use of an `isolated` parameter to accept an actor instance and execute code on its specific executor. This allows functions to operate within the caller's isolation context without being tied to a particular actor. ```swift func updateUI(on actor: isolated MainActor) { // Runs on the main actor } ``` -------------------------------- ### Create AsyncStream with makeStream factory Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/async-streams.md Use the static `makeStream(of:)` factory method to create an AsyncStream and its continuation. This is the modern and preferred approach over closure-based creation. ```swift let (stream, continuation) = AsyncStream.makeStream(of: Event.self) ``` -------------------------------- ### Create AsyncStream with Buffering Policy Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/async-streams.md Specify a buffering policy when creating an `AsyncStream` to manage memory usage and back pressure. `.bufferingNewest(100)` keeps the 100 most recent elements. ```swift let (stream, continuation) = AsyncStream.makeStream( of: SensorReading.self, bufferingPolicy: .bufferingNewest(100) ) ``` -------------------------------- ### Confirming Async Events with confirmation() Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/testing.md Use `confirmation()` to test if an asynchronous event fires, such as a callback or notification. This replaces older XCTest expectation patterns. Ensure all async work completes before the `confirmation()` closure returns. ```swift @Test func notificationFires() async { await confirmation { confirmed in // Start listening before posting, and yield to ensure // the for-await loop is actually iterating before the // notification is sent. Without the yield the post can // arrive before the listener is ready, making the test flaky. let task = Task { for await _ in NotificationCenter.default.notifications(named: .dataDidChange) { confirmed() break } } // Give the task a chance to reach its first suspension // inside the for-await loop. await Task.yield() NotificationCenter.default.post(name: .dataDidChange, object: nil) await task.value } } ``` -------------------------------- ### Protecting Global State with @MainActor Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/actors.md Illustrates how to protect global static state using the @MainActor annotation. This ensures that access to shared resources like `Library.shared` is confined to the main thread, which is crucial for UI-related code. ```swift @MainActor final class Library { static let shared = Library() var books = [Book]() } ``` -------------------------------- ### Async Test Function Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/testing.md Write async tests directly by marking test functions with `async`. Avoid wrapping async work in `Task {}` or using manual synchronization primitives. ```swift @Test func userLoads() async throws { let user = try await UserService().load(id: "123") #expect(user.name == "Alice") } ``` -------------------------------- ### Main Actor Isolated Protocol Conformance Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/diagnostics.md Apply this when a protocol conformance should only be usable on the MainActor. This ensures that protocol methods are called with the correct actor isolation. ```swift extension MyType: @MainActor SomeProtocol {} ``` -------------------------------- ### Naming Tasks for Debugging Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/new-features.md Assign a name to a Task using the 'name' parameter for easier identification in logs and debugging. This is helpful when diagnosing issues with specific tasks. ```swift let task = Task(name: "MyTask") { print("Current task name: \(Task.name ?? \"Unknown\")") } ``` -------------------------------- ### Wrap Synchronous Code in Task Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/diagnostics.md If a call needs to be made asynchronously but the surrounding code cannot be made async, wrap the call in a Task. Be mindful of when this is appropriate, as detailed in unstructured.md. ```swift Task { await someActor.someMethod() } ``` -------------------------------- ### Test Cancellation Handling in Swift Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/testing.md Verify that your code correctly checks for cancellation by canceling the task while it's performing work and asserting that it throws `CancellationError`. ```swift @Test func processorRespectsCancel() async throws { // Processor.run() calls Task.checkCancellation() between items. // Feed it enough work that cancellation will be checked mid-flight. let processor = Processor(items: Array(repeating: .stub, count: 1_000)) let task = Task { try await processor.run() } // Let the processor start, then cancel. try await Task.sleep(for: .zero) task.cancel() await #expect(throws: CancellationError.self) { try await task.value } } ``` -------------------------------- ### Specific Actor Isolation with confirmation() Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/testing.md Use the `isolation` parameter in `confirmation()` for finer control over actor isolation, allowing a specific closure to run on a designated actor while the rest of the test executes elsewhere. ```swift @Test func loadingUpdatesUI() async { await confirmation(isolation: MainActor.shared) { confirmed in let vm = ViewModel(onUpdate: { confirmed() }) await vm.load() } } ``` -------------------------------- ### Wrap completion handlers with `withCheckedThrowingContinuation` Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/interop.md Use `withCheckedThrowingContinuation` to wrap existing completion handler APIs. Ensure the continuation is resumed exactly once on every path. This is useful when the SDK does not provide an async overload. ```swift func loadUser(id: String) async throws -> User { try await withCheckedThrowingContinuation { continuation in api.fetchUser(id: id) { result in continuation.resume(with: result) } } } ``` -------------------------------- ### Corrected Actor: Handling State After Await Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/actors.md Shows the correct way to handle actor state after an await by capturing the result in a local variable before assignment. This prevents issues caused by state changes during suspension. ```swift actor VideoCache { var items: [URL: Video] = [: ] func video(for url: URL) async throws -> Video { if let cached = items[url] { return cached } let video = try await downloadVideo(url) items[url] = video return video } } ``` -------------------------------- ### Annotate Static Property with @MainActor Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/diagnostics.md Use this to make global or static variables safe for access from multiple isolation domains. This is the simplest code-local fix for static property safety issues. ```swift @MainActor static let shared = MyType() ``` -------------------------------- ### Replace `DispatchQueue.global().async` with `@concurrent` Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/interop.md For one-off background computations, use the `@concurrent` attribute (available in Swift 6.2) to offload CPU work. For parallel batch work, use `withTaskGroup`. ```swift // Before DispatchQueue.global().async { let result = heavyComputation() DispatchQueue.main.async { self.result = result } } // After (Swift 6.2) @concurrent func heavyComputation() async -> ComputationResult { ... } // At call site: self.result = await heavyComputation() ``` -------------------------------- ### Naming Tasks in Task Groups Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/new-features.md Name individual tasks added to a TaskGroup for better traceability. This allows you to identify specific child tasks when logging or debugging failures within the group. ```swift let stories = await withTaskGroup { group -> [NewsStory] in for i in 1...5 { group.addTask(name: "Stories \(i)") { do { let url = URL(string: "https://hws.dev/news-\(i).json")! let (data, _) = try await URLSession.shared.data(from: url) return try JSONDecoder().decode([NewsStory].self, from: data) } catch { print("Loading \(Task.name ?? \"Unknown\") failed.") return [] } } } var allStories = [NewsStory]() for await stories in group { allStories.append(contentsOf: stories) } return allStories } ``` -------------------------------- ### Structured Concurrency with Task Groups in Swift Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/SKILL.md Replaces unstructured tasks created in a loop with a `withThrowingTaskGroup` for better cancellation propagation and structured concurrency. This ensures that if one task fails, the entire group can be cancelled. ```swift for url in urls { Task { try await fetch(url) } } ``` ```swift try await withThrowingTaskGroup(of: Data.self) { group in for url in urls { group.addTask { try await fetch(url) } } for try await result in group { process(result) } } ``` -------------------------------- ### Main Actor Isolation Default Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/new-features.md Opt a module into main-actor isolation by default. This applies `@MainActor` implicitly to most declarations unless explicitly opted out. ```swift @MainActor class User: @MainActor Equatable { var id: UUID var name: String init(name: String) { self.id = UUID() self.name = name } static func ==(lhs: User, rhs: User) -> Bool { lhs.id == rhs.id } } ``` -------------------------------- ### Actor Reentrancy: Check-Then-Act Across Await Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/bug-patterns.md Avoid checking actor state, awaiting, and then acting on stale data. Use structured concurrency to capture results before mutation. ```swift // BUG: Two callers can both see nil and both download. // The force unwrap can crash if a third caller clears the cache mid-flight. actor Cache { var data: [String: Data] = [:] func load(_ key: String) async throws -> Data { if data[key] == nil { data[key] = try await download(key) } return data[key]! } } ``` -------------------------------- ### Migrate serial `DispatchQueue` to `actor` Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/interop.md A serial dispatch queue protecting mutable state can be directly mapped to an `actor`. This provides built-in isolation for the state. ```swift // Before class TokenStore { private let queue = DispatchQueue(label: "token-store") private var token: String? func setToken(_ t: String) { queue.sync { token = t } } func getToken() -> String? { queue.sync { token } } } // After actor TokenStore { private var token: String? func setToken(_ t: String) { token = t } func getToken() -> String? { token } } ``` -------------------------------- ### Structured Concurrency with `withTaskGroup` in Swift Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/skills/swift-concurrency-pro/SKILL.md Replaces unstructured `Task {}` creation within a loop with `withTaskGroup` for better cancellation propagation and structured concurrency. This is preferred over creating tasks individually. ```swift // Before for url in urls { Task { try await fetch(url) } } // After try await withThrowingTaskGroup(of: Data.self) { group in for url in urls { group.addTask { try await fetch(url) } } for try await result in group { process(result) } } ``` -------------------------------- ### Handling Cancellation with a Cancellable Handle Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/cancellation.md This pattern is useful when wrapping APIs that return a cancellable handle, such as `CKQueryOperation`. The `onCancel` closure is used to explicitly cancel the operation. ```swift func observe() async throws -> [Change] { let query = CKQuery(recordType: "Item", predicate: NSPredicate(value: true)) let operation = CKQueryOperation(query: query) return try await withTaskCancellationHandler { try await performOperation(operation) } onCancel: { operation.cancel() } ``` -------------------------------- ### Broken Cancellation: No Checks in CPU-Bound Work Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/cancellation.md CPU-bound loops without `await` points will not be cancellable. Insert periodic `try Task.checkCancellation()` calls within such loops to allow for cancellation. ```swift A tight computational loop with no `await` points will run to completion even if cancelled, because there are no suspension points where cancellation can take effect. Insert periodic `try Task.checkCancellation()` calls wherever it’s safe. ``` -------------------------------- ### Update `DispatchQueue.main.async` to `@MainActor` Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/interop.md Replace `DispatchQueue.main.async` calls with the `@MainActor` attribute on the enclosing function or type to ensure UI updates happen on the main thread. If called from a non-isolated async context, `await` handles the dispatch. ```swift // Before DispatchQueue.main.async { self.label.text = "Done" } // After – make the enclosing function or type @MainActor @MainActor func updateLabel() { label.text = "Done" } ``` ```swift await updateLabel() ``` -------------------------------- ### Error Handling with Partial Results in Swift Task Groups Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/structured.md To obtain partial results when child tasks might fail, catch errors within each child task and return them as part of the result. This allows the parent task to handle both successful and failed child operations. ```swift await withTaskGroup(of: (URL, Result).self) { group in for url in urls { group.addTask { do { return (url, .success(try await fetch(url))) } catch { return (url, .failure(error)) } } } for await (url, result) in group { switch result { case .success(let data): handle(data) case .failure(let error): log(error, for: url) } } } ``` -------------------------------- ### Testing Actor State Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/testing.md Access actor properties using `await` within tests, mirroring production code. Do not use `nonisolated` accessors solely for testing. ```swift @Test func cachingWorks() async throws { let cache = ImageCache() let image = try await cache.image(for: testURL) let cached = try await cache.image(for: testURL) #expect(image == cached) } ``` -------------------------------- ### Checking for Cancellation in a Loop Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/cancellation.md Use `try Task.checkCancellation()` inside loops for long-running or asynchronous work to allow tasks to be cancelled safely. This is preferred in throwing contexts. ```swift func processAll(_ items: [Item]) async throws { for item in items { try Task.checkCancellation() try await process(item) } } ``` -------------------------------- ### Handle Errors in Task Closures Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/bug-patterns.md Ensure errors thrown within Task closures are caught and handled to prevent silent failures. Log errors or update UI state. ```swift Task { do { try await riskyWork() } catch { self.errorMessage = error.localizedDescription } } ``` -------------------------------- ### Add 'await' for Async Calls Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/diagnostics.md Use this when a call crosses an isolation boundary and requires an asynchronous hop. This is necessary when calling actor-isolated methods from outside the actor or accessing @MainActor state from a non-isolated context. ```swift await someActor.someMethod() ``` -------------------------------- ### Provide Test Scope with Task-Local Values Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/testing.md Use a custom trait conforming to `TestTrait` and `TestScoping` to provide scoped task-local values for tests. This ensures independent configurations for parallel tests. ```swift struct MockEnvironmentTrait: TestTrait, TestScoping { func provideScope( for test: Test, testCase: Test.Case?, performing function: () async throws -> Void ) async throws { let env = Environment(apiBase: URL(string: "https://test.example.com")!) try await Environment.$current.withValue(env) { try await function() } } } extension Trait where Self == MockEnvironmentTrait { static var mockEnvironment: Self { Self() } } ``` ```swift @Test(.mockEnvironment) func fetchUsesTestAPI() async throws { // Environment.current is now the mock, scoped to this test's task. let users = try await UserService().fetchAll() #expect(users.isEmpty == false) } ``` -------------------------------- ### Offloading Work with @concurrent Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/new-features.md Use `@concurrent` for CPU-heavy work that should leave the caller's actor and run on the concurrent pool. It is not intended for ordinary async I/O. ```swift nonisolated struct Measurements { @concurrent func analyzeReadings(_ readings: [Double]) async -> AnalysisResult { ... } } let result = await Measurements().analyzeReadings(readings) ``` -------------------------------- ### Avoid Timing-Based Tests in Swift Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/testing.md Do not use `Task.sleep` or fixed delays to wait for asynchronous operations. Instead, await the actual asynchronous work to ensure reliable tests. ```swift // BROKEN: Relies on timing. @Test func dataLoads() async throws { viewModel.load() try await Task.sleep(for: .seconds(1)) #expect(viewModel.items.isEmpty == false) } ``` ```swift // CORRECT: Awaits the real work. @Test func dataLoads() async throws { await viewModel.load() #expect(viewModel.items.isEmpty == false) } ``` -------------------------------- ### Isolated Deinitializer for Actor-Isolated Classes Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/new-features.md Mark a deinitializer with 'isolated' to ensure it runs on the class's actor, allowing safe access to actor-protected state. This is crucial for classes marked with @MainActor or other actor isolation. ```swift @MainActor class Session { let user: User init(user: User) { self.user = user user.isLoggedIn = true } isolated deinit { // Runs on the main actor, so accessing user is safe. user.isLoggedIn = false } } ``` -------------------------------- ### Handling Cancellation with URLSession Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/cancellation.md Use `withTaskCancellationHandler` to bridge Swift's cancellation to legacy APIs. The `onCancel` closure is called when cancellation is requested. For `URLSession.shared.data(for:)`, cancellation is handled internally, making the `onCancel` block less critical for this specific API. ```swift func fetchImage(_ url: URL) async throws -> Data { var request = URLRequest(url: url) return try await withTaskCancellationHandler { let (data, _) = try await URLSession.shared.data(for: request) return data } onCancel: { // No direct handle to cancel here – URLSession.data(for:) already // checks for task cancellation internally. This pattern is most // useful when wrapping APIs that return a cancellable handle. } ``` -------------------------------- ### Task Priority Escalation Handler Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/new-features.md Use withTaskPriorityEscalationHandler to observe and react to task priority changes. The handler is called when a task's priority is escalated, providing the old and new priorities. ```swift let newsFetcher = Task(priority: .medium) { try await withTaskPriorityEscalationHandler { let url = URL(string: "https://hws.dev/messages.json")! let (data, _) = try await URLSession.shared.data(from: url) return data } onPriorityEscalated: { oldPriority, newPriority in print("Priority has been escalated to \(newPriority)") } } newsFetcher.escalatePriority(to: .high) ``` -------------------------------- ### Nonisolated Async Stays on Caller's Actor Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/new-features.md In Swift 6.2, a plain `async` function on an owned helper now stays on the caller's actor by default, rather than automatically offloading. Explicit offloading is required if the old behavior is desired. ```swift struct Measurements { func fetchLatest() async throws -> [Double] { let url = URL(string: "https://hws.dev/readings.json")! let (data, _) = try await URLSession.shared.data(from: url) return try JSONDecoder().decode([Double].self, from: data) } } @MainActor struct WeatherStation { let measurements = Measurements() func getAverageTemperature() async throws -> Double { let readings = try await measurements.fetchLatest() return readings.reduce(0, +) / Double(readings.count) } } ``` -------------------------------- ### Buggy Actor: Reentrancy Issue Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/actors.md Demonstrates a common reentrancy bug in actors where state is assumed unchanged after an await. This can lead to duplicate work or crashes if another caller modifies the state. ```swift actor VideoCache { var items: [URL: Video] = [: ] func video(for url: URL) async throws -> Video { if items[url] == nil { items[url] = try await downloadVideo(url) } return items[url]! } } ``` -------------------------------- ### Parameterized Test with .serialized Trait Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/testing.md Use the `.serialized` trait to control the execution order of parameterized test cases. Note that `.serialized` only affects parameterized tests and has no effect on non-parameterized ones. ```swift // .serialized controls execution order of parameterized cases only. @Test(.serialized, arguments: ["alice", "bob", "charlie"]) async throws { let account = try await AccountService().create(username: username) #expect(account.isActive) } ``` -------------------------------- ### Main Actor Isolation for Tests Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/testing.md Mark individual tests or entire suites with `@MainActor` when testing code that requires main-actor isolation. This ensures the test runs on the main actor. ```swift @MainActor @Test func viewModelUpdatesOnMainActor() async { let vm = ViewModel() await vm.refresh() #expect(vm.items.isEmpty == false) } ``` -------------------------------- ### Cooperative Cancellation Check Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/unstructured.md Tasks must explicitly check for cancellation. Task.checkCancellation() throws CancellationError if cancelled, while Task.isCancelled returns a Bool. ```swift func processItems(_ items: [Item]) async throws { for item in items { // Check before expensive work try Task.checkCancellation() await process(item) } } ``` -------------------------------- ### Asserting Execution on MainActor Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/actors.md Use MainActor.assertIsolated() within a function to halt execution in debug builds if the code is not running on the MainActor. This method has no impact on release builds. ```swift func refresh() { MainActor.assertIsolated() // do your work here } ``` -------------------------------- ### Task vs Task.detached Actor Isolation Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/unstructured.md Task inherits the caller's actor isolation, while Task.detached does not. Use Task.detached only when you need to shed the caller's context and priority. ```swift @MainActor func example() { Task { // Still on MainActor; safe to update UI here. label.text = "Done" } Task.detached { // Not on MainActor; updating UI here is a bug. // Use this for genuinely independent background work. } } ``` -------------------------------- ### Ignore CancellationError in Catch Blocks Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/bug-patterns.md Distinguish between normal cancellation and other errors. Do not retry or show alerts for CancellationError, as it indicates a normal lifecycle event. ```swift do { try await loadData() } catch is CancellationError { // Normal – view disappeared or task was cancelled. Do nothing. } catch { self.errorMessage = error.localizedDescription } ``` -------------------------------- ### Broken Cancellation: Ignoring CancellationError Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/cancellation.md Avoid catching and ignoring `CancellationError` as it represents a normal lifecycle event, not a typical error to be retried or alerted upon. ```swift // BROKEN: Retries or shows an alert for a normal lifecycle event. catch { showAlert(error.localizedDescription) } ``` -------------------------------- ### Using withDiscardingTaskGroup for Side-Effect Tasks in Swift Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/references/structured.md Use `withDiscardingTaskGroup` for child tasks that do not return meaningful results (fire-and-forget operations). This avoids accumulating unused results in memory, making it preferred for side-effect-only tasks. ```swift // Preferred for side-effect-only child tasks await withDiscardingTaskGroup { group in for connection in connections { group.addTask { await connection.sendHeartbeat() } } } ``` -------------------------------- ### Actor Reentrancy Fix in Swift Source: https://github.com/twostraws/swift-concurrency-agent-skill/blob/main/swift-concurrency-pro/SKILL.md Fixes an actor reentrancy issue where state might change between checking and accessing it. This prevents potential race conditions and force-unwrap crashes. ```swift actor Cache { var items: [String: Data] = [: ] func fetch(_ key: String) async throws -> Data { if items[key] == nil { items[key] = try await download(key) } return items[key]! } } ``` ```swift actor Cache { var items: [String: Data] = [: ] func fetch(_ key: String) async throws -> Data { if let existing = items[key] { return existing } let data = try await download(key) items[key] = data return data } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.