### Setup and Teardown with init/deinit Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/testing.md Utilize `init` for asynchronous setup and `deinit` for synchronous cleanup in test classes. Note that `deinit` cannot call async methods. ```swift @MainActor final class DatabaseTests { let database: Database init() async throws { database = Database() await database.prepare() } deinit { // Synchronous cleanup only } @Test func insertsData() async throws { try await database.insert(item) #expect(await database.count() == 1) } } ``` -------------------------------- ### Install Swift Concurrency Skill using pi package manager Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/README.md Install the Swift Concurrency Agent Skill using the pi package manager. The skill will be automatically available in pi sessions after installation. ```bash pi install https://github.com/AvdLee/Swift-Concurrency-Agent-Skill ``` -------------------------------- ### Async Setup and Teardown in XCTest Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/testing.md Implement asynchronous setup and teardown methods in XCTest subclasses by marking `setUp()` and `tearDown()` with `async throws`. This enables calling asynchronous methods during setup and cleanup. ```swift final class DatabaseTests: XCTestCase { override func setUp() async throws { // Async setup } override func tearDown() async throws { // Async teardown } } ``` -------------------------------- ### Migrate XCTest Setup/Teardown to Swift Testing Traits Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/testing.md Demonstrates how to implement setup logic using a custom TestTrait in Swift Testing, replacing the traditional `setUp` method from XCTest. ```swift // XCTest override func setUp() async throws { await prepare() } // Swift Testing struct SetupTrait: TestTrait, TestScoping { func provideScope( for test: Test, testCase: Test.Case?, performing function: () async throws -> Void ) async throws { await prepare() try await function() } } ``` -------------------------------- ### Install skill-creator Skill Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/CONTRIBUTING.md Use this command to install the skill-creator skill if you are using skills.sh. This tool helps ensure contributions follow the Agent Skills format. ```bash npx skills add https://github.com/anthropics/skills --skill skill-creator ``` -------------------------------- ### AsyncAlgorithms Package Installation Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md Shows how to add the AsyncAlgorithms package to your project's dependencies and import it into your target. ```swift dependencies: [ .package(url: "https://github.com/apple/swift-async-algorithms", from: "1.0.0") ] targets: [ .target( name: "MyTarget", dependencies: [ .product(name: "AsyncAlgorithms", package: "swift-async-algorithms") ] ) ] ``` -------------------------------- ### Install Swift Concurrency Skill in Claude Code Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/README.md Install the Swift Concurrency Agent Skill after adding its marketplace to Claude Code. This makes the skill available for use. ```bash /plugin install swift-concurrency@swift-concurrency-agent-skill ``` -------------------------------- ### Correct Task Isolation: Concurrent Start with UI Hop Back Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/SKILL.md Illustrates the recommended approach for tasks not starting on the main actor, hopping back only for UI updates. ```swift Task { @concurrent in await hopToOtherIsolationDomain() await MainActor.run { updateUI() } } ``` -------------------------------- ### Start Async Work from Synchronous Code Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/tasks.md Use `Task` to start asynchronous operations from synchronous code. Tasks begin execution immediately upon creation. ```swift func synchronousMethod() { Task { await someAsyncMethod() } } ``` -------------------------------- ### Start Synchronous Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/performance.md Begin with synchronous code for fast, in-memory operations. Only move to asynchronous execution if profiling indicates a need. ```swift // Start here func processData(_ data: Data) -> Result { // Fast, in-memory work } ``` -------------------------------- ### Basic Retain Cycle Example Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/memory-management.md Demonstrates a classic retain cycle between two classes, `A` and `B`, where each holds a strong reference to the other, preventing deallocation. ```swift class A { var b: B? } class B { var a: A? } let a = A() let b = B() a.b = b b.a = a // Retain cycle - neither can be deallocated ``` -------------------------------- ### Add Swift Concurrency Skill using skills.sh Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/README.md Install the Swift Concurrency Agent Skill using the skills.sh command-line tool. This is the recommended method for integrating the skill. ```bash npx skills add https://github.com/avdlee/swift-concurrency-agent-skill --skill swift-concurrency ``` -------------------------------- ### Xcode Migration Warning Example Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md Illustrates a typical warning generated during Xcode's migration process for upcoming features, showing the 'before' and 'after' code structure. ```swift // ⚠️ Use of protocol 'Error' as a type must be written 'any Error' func fetchData() throws -> Data // Before func fetchData() throws -> any Data // After applying fix ``` -------------------------------- ### Combine Form Validation Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md This example demonstrates form validation using Combine's Publishers.CombineLatest2. It requires importing Combine. ```swift import Combine final class FormValidator: ObservableObject { @Published var username = "" @Published var email = "" @Published private(set) var formState: FormState = .incomplete init() { Publishers.CombineLatest2($username, $email) .map { username, email in validate(username: username, email: email) } .assign(to: &$formState) } } ``` -------------------------------- ### Incorrect Task Isolation: Empty Synchronous Prefix Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/SKILL.md This example shows an incorrect approach where an empty synchronous prefix leads to an unnecessary hop away from the main actor. ```swift Task { await hopToOtherIsolationDomain() } ``` -------------------------------- ### Manual Closure-Based Function Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md Example of a function using traditional closure-based completion handlers for asynchronous operations. ```swift func fetchImage(urlRequest: URLRequest, completion: @escaping @Sendable (Result) -> Void) { URLSession.shared.dataTask(with: urlRequest) { data, _, error in do { if let error = error { throw error } guard let data = data, let image = UIImage(data: data) else { throw ImageError.conversionFailed } completion(.success(image)) } catch { completion(.failure(error)) } }.resume() } ``` -------------------------------- ### Rewritten Async/Await Function Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md The same functionality as the closure-based example, but rewritten using Swift's async/await syntax for improved readability and error handling. ```swift func fetchImage(urlRequest: URLRequest) async throws -> UIImage { let (data, _) = try await URLSession.shared.data(for: urlRequest) guard let image = UIImage(data: data) else { throw ImageError.conversionFailed } return image } ``` -------------------------------- ### Add Swift Concurrency Skill Marketplace for Claude Code Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/README.md Add the Swift Concurrency Agent Skill marketplace for personal use within Claude Code. This allows for easier installation of the skill. ```bash /plugin marketplace add AvdLee/Swift-Concurrency-Agent-Skill ``` -------------------------------- ### Throttle Operator Example: Like Button Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md Shows how to use the `throttle` operator to limit the rate at which an action can be performed, such as toggling a like button. This prevents multiple rapid taps from triggering the action excessively. ```swift import AsyncAlgorithms struct LikeButton: View { @State private var tapStream = AsyncStream { continuation in // Continuation stored externally } @State private var isLiked = false var body: some View { Button(action: { tapStream.continuation?.yield() }) { Image(systemName: isLiked ? "heart.fill" : "heart") } .task { await handleThrottledTaps() } } private func handleThrottledTaps() async { for await _ in tapStream.throttle(for: .seconds(1)) { await toggleLike() } } private func toggleLike() async { isLiked.toggle() await APIClient.updateLikeStatus(isLiked: isLiked) } } ``` -------------------------------- ### Quick Start: Top 5 AsyncAlgorithms Operators Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md Demonstrates the top 5 most common operators in AsyncAlgorithms: debounce, throttle, merge, combineLatest, and zip. These are useful for handling rapid inputs, repeated actions, and combining multiple asynchronous streams. ```swift import AsyncAlgorithms // 1. Debounce rapid inputs for await query in searchQueryStream.debounce(for: .milliseconds(500)) { await performSearch(query) } ``` ```swift // 2. Throttle repeated actions for await _ in buttonClicks.throttle(for: .seconds(1)) { await performAction() } ``` ```swift // 3. Merge multiple independent streams for await message in chat1Messages.merge(chat2Messages) { display(message) } ``` ```swift // 4. Combine dependent values for await (username, email) in usernameStream.combineLatest(emailStream) { validateForm(username: username, email: email) } ``` ```swift // 5. Zip paired operations for await (image, metadata) in imageStream.zip(metadataStream) { await cache(image: image, metadata: metadata) } ``` -------------------------------- ### WebSocket Example with AsyncThrowingChannel Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md Demonstrates how to use AsyncThrowingChannel to create a WebSocket connection that streams messages and handles errors asynchronously. The `getMessages()` method provides an `AsyncThrowingStream` for receiving messages, and `receiveMessage()` and `reportError()` are used to send data or signal completion with an error. ```swift import AsyncAlgorithms actor WebSocketConnection { private let channel = AsyncThrowingChannel() func getMessages() -> AsyncThrowingStream { channel } func receiveMessage(_ message: WebSocketMessage) async { await channel.send(message) } func reportError(_ error: Error) async { await channel.finish(throwing: error) } } // Usage do { for await message in connection.getMessages() { handle(message) } } catch { print("WebSocket error: \(error)") } ``` -------------------------------- ### Rethinking Complex Pipelines with Swift Concurrency Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md This example contrasts a complex Combine pipeline with a simpler Swift Concurrency approach for handling asynchronous data streams. It emphasizes rethinking the problem rather than directly translating operators. ```swift // ❌ Looking for AsyncSequence equivalent of complex Combine pipeline somePublisher .debounce(for: .seconds(0.5)) .removeDuplicates() .flatMap { ... } .sink { ... } // ✅ Rethink the problem with Swift Concurrency Task { var lastValue: String? for await value in stream { guard value != lastValue else { continue } lastValue = value try await Task.sleep(for: .seconds(0.5)) await process(value) } } ``` -------------------------------- ### Data Race Prevention with Actors Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/sendable.md This example demonstrates how to prevent data races by using an actor to manage shared mutable state, contrasting with unsafe concurrent access. ```swift // ⚠️ Data race var counter = 0 DispatchQueue.global().async { counter += 1 } DispatchQueue.global().async { counter += 1 } ``` ```swift actor Counter { private var value = 0 func increment() { value += 1 } } ``` -------------------------------- ### Basic AsyncSequence Iteration Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-sequences.md Iterate over values from an async sequence where values may arrive over time. No special setup is required if the sequence is already defined. ```swift for await value in someAsyncSequence { print(value) } ``` -------------------------------- ### Task Group for Concurrent Operations Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-sequences.md Use a task group to concurrently perform operations and collect their results. This example downloads multiple images in parallel. ```swift await withTaskGroup(of: Image.self) { group in for url in urls { group.addTask { await download(url) } } for await image in group { display(image) } } ``` -------------------------------- ### Actor-Isolated Class Example Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/sendable.md Actors provide a dedicated isolation domain with serialized access to their state. External access to actor methods requires `await`. ```swift actor Library { var books: [String] = [] func addBook(_ title: String) { books.append(title) } } // External access requires await await library.addBook("Swift Concurrency") ``` -------------------------------- ### Debouncing Search Queries with Combine Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md This example shows how to debounce user input for search queries using Combine's debounce operator. It ensures that the search function is only called after a period of inactivity. ```swift $searchQuery .debounce(for: .milliseconds(500), scheduler: DispatchQueue.main) .sink { [weak self] query in self?.performSearch(query) } .store(in: &cancellables) ``` -------------------------------- ### Polling Service with Task Management Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/memory-management.md Implement a polling service that starts and stops a background task. Ensure `[weak self]` is used to prevent retain cycles when capturing `self` in the task closure. ```swift final class PollingService { private var task: Task? func start() { task = Task { [weak self] in while let self = self { await self.poll() try? await Task.sleep(for: .seconds(5)) } } } func stop() { task?.cancel() } } ``` -------------------------------- ### Mixed Sequential and Parallel Execution Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/tasks.md Combine sequential and parallel execution patterns. First, perform a sequential operation, then launch parallel tasks based on the result. This is useful for workflows where initial setup is required before parallel processing. ```swift let user = try await fetchUser() async let posts = fetchPosts(userId: user.id) async let followers = fetchFollowers(userId: user.id) let profile = Profile( user: user, posts: try await posts, followers: try await followers ) ``` -------------------------------- ### Concurrent Execution with async let in Swift Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-await-basics.md Use `async let` to initiate multiple asynchronous operations concurrently. The operations start immediately, and their results are retrieved later using `await`. This is suitable when tasks do not depend on each other. ```swift async let data1 = fetchData(1) async let data2 = fetchData(2) async let data3 = fetchData(3) let results = try await [data1, data2, data3] ``` -------------------------------- ### Debouncing Search Queries with Swift Concurrency Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md This Swift Concurrency example debounces search queries using Task.sleep. It cancels any previous search task before starting a new one after a delay. ```swift func search(_ query: String) { currentSearchTask?.cancel() currentSearchTask = Task { do { try await Task.sleep(for: .milliseconds(500)) performSearch(query) } catch { // Search was cancelled } } } ``` -------------------------------- ### Clone the Repository Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/CONTRIBUTING.md To set up the project for local development and testing, clone the repository to your local machine. Ensure you navigate into the cloned directory afterwards. ```bash git clone https://github.com/avdlee/swift-concurrency-agent-skill.git cd swift-concurrency-agent-skill ``` -------------------------------- ### Migrating Actor Isolation Issues to Swift Concurrency Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md This example shows the recommended way to handle notifications using Swift Concurrency. By using `NotificationCenter.default.notifications(named:)` within a Task, actor isolation is correctly maintained, preventing potential crashes. ```swift Task { [weak self] in for await _ in NotificationCenter.default.notifications(named: .someNotification) { await self?.handleNotification() // ✅ Compile-time safe } } ``` -------------------------------- ### Sequential vs. Parallel Download Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/performance.md Demonstrates how to replace sequential downloads with a parallel approach using `withTaskGroup` for improved performance. ```swift // ❌ Sequential for url in urls { let image = await download(url) images.append(image) } // ✅ Parallel await withTaskGroup(of: Image.self) { group in for url in urls { group.addTask { await download(url) } } for await image in group { images.append(image) } } ``` -------------------------------- ### Synchronous vs. Asynchronous vs. Parallel Execution Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/performance.md Illustrates the progression from synchronous to asynchronous and finally to parallel execution. Move to more complex execution styles only when necessary and proven by measurement. ```text Synchronous → Asynchronous → Parallel ``` -------------------------------- ### Nonisolated Function Example Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/sendable.md Functions without explicit isolation restrictions run in the nonisolated domain. They cannot modify isolated state. ```swift func computeValue(a: Int, b: Int) -> Int { return a + b } ``` -------------------------------- ### Race Condition Example Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/sendable.md Illustrates a race condition where timing-dependent behavior leads to unpredictable results, even when data races are prevented. ```swift let counter = Counter() for _ in 1...10 { Task { await counter.increment() } } // May print inconsistent values print(await counter.getValue()) ``` -------------------------------- ### Combine to AsyncAlgorithms: Multi-Source Loading with TaskGroup Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md Migrates a multi-source item loading mechanism from Combine's `Publishers.Merge` to AsyncAlgorithms' `TaskGroup`. This approach allows for parallel fetching of items from multiple sources, aggregating the results efficiently. ```swift import Combine final class ArticleLoader: ObservableObject { @Published private(set) var items: [Item] = [] func loadAllSources() { let source1 = APIClient.fetchItems(from: .source1) let source2 = APIClient.fetchItems(from: .source2) Publishers.Merge(source1, source2) .scan([]) { accumulated, new in accumulated + new } .receive(on: DispatchQueue.main) .assign(to: &$items) } } ``` ```swift import AsyncAlgorithms @Observable final class ArticleLoader { @MainActor private(set) var items: [Item] = [] func loadAllSourcesParallel() async { await withTaskGroup(of: [Item].self) { group in group.addTask { await APIClient.fetchItems(from: .source1) } group.addTask { await APIClient.fetchItems(from: .source2) } for await newItems in group { items.append(contentsOf: newItems) } } } } ``` -------------------------------- ### Avoid Manual Timer Implementation Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md This anti-pattern demonstrates a manual, less robust way to implement timers. Prefer using AsyncTimerSequence for better reliability and cancellation handling. ```swift // Bad: Manual timer implementation func startTimer() { Task { while !Task.isCancelled { performAction() try? await Task.sleep(for: .seconds(1)) } } } ``` -------------------------------- ### Configure Project for Swift Concurrency Skill in Claude Code Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/README.md Automatically provide the Swift Concurrency Agent Skill to all collaborators in a repository by configuring the .claude/settings.json file. This ensures consistent access to the skill. ```json { "enabledPlugins": { "swift-concurrency@swift-concurrency-agent-skill": true }, "extraKnownMarketplaces": { "swift-concurrency-agent-skill": { "source": { "source": "github", "repo": "AvdLee/Swift-Concurrency-Agent-Skill" } } } } ``` -------------------------------- ### Demonstrate Thread Switching After Suspension Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/threading.md Illustrates how a task can resume on a different thread after an `await` suspension point. This highlights the importance of the `Sendable` protocol for ensuring type safety across thread boundaries. ```swift func example() async { print("Thread 1: \(Thread.current)") await someWork() print("Thread 2: \(Thread.current)") // Different thread } ``` -------------------------------- ### View Model with @MainActor Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/actors.md Use @MainActor for view models to ensure UI updates are performed on the main thread. This requires no special setup beyond the attribute. ```swift @MainActor final class ContentViewModel: ObservableObject { @Published var items: [Item] = [] func loadItems() async { items = try await api.fetchItems() } } ``` -------------------------------- ### AsyncAlgorithms Form Validation (Stream) Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md This example shows continuous form validation using AsyncAlgorithms' combineLatest operator. It requires importing AsyncAlgorithms and uses @Observable. ```swift import AsyncAlgorithms @Observable final class FormValidator { var username = "" var email = "" @MainActor private(set) var formState: FormState = .incomplete // Option 1: combineLatest for stream-based validation func startStreamValidation() { Task { @MainActor in for await (username, email) in usernameStream.combineLatest(emailStream) { self.formState = validate( username: username, email: email ) } } } // Option 2: async let for simple validation func validateForm() async { let (username, email) = await (username, email) formState = validate( username: username, email: email ) } } ``` -------------------------------- ### Basic Task Group Usage Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/tasks.md Create a task group to dynamically launch multiple child tasks. The group manages the lifecycle of these tasks, ensuring they are all awaited. ```swift await withTaskGroup(of: UIImage.self) { group in for url in photoURLs { group.addTask { await downloadPhoto(url: url) } } } ``` -------------------------------- ### Global Actor-Isolated Function Example Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/sendable.md Global actors, like `@MainActor`, provide a shared isolation domain across types, often used for UI updates. ```swift @MainActor func updateUI() { // Runs on main thread } ``` -------------------------------- ### Create Unstructured and Detached Tasks Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/tasks.md Demonstrates creating regular tasks that inherit context and detached tasks that run independently. Detached tasks are useful for background work that should continue even if the parent task is cancelled. ```swift // Regular task (unstructured but inherits priority) let task = Task { await doWork() } // Detached task (completely independent) Task.detached(priority: .background) { await cleanup() } ``` ```swift Task.detached(priority: .background) { await DirectoryCleaner.cleanup() } ``` -------------------------------- ### Bridge CLLocationManager Delegate to AsyncStream Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-sequences.md Wrap a CLLocationManager delegate pattern into an AsyncThrowingStream to receive location updates asynchronously. Ensure the delegate is set and location updates are started. ```swift final class LocationMonitor: NSObject { private var continuation: AsyncThrowingStream.Continuation? let stream: AsyncThrowingStream override init() { var capturedContinuation: AsyncThrowingStream.Continuation? stream = AsyncThrowingStream { continuation in capturedContinuation = continuation } super.init() self.continuation = capturedContinuation locationManager.delegate = self locationManager.startUpdatingLocation() } } extension LocationMonitor: CLLocationManagerDelegate { func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { for location in locations { continuation?.yield(location) } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { continuation?.finish(throwing: error) } } // Usage let monitor = LocationMonitor() for try await location in monitor.stream { print("Location: \(location.coordinate)") } ``` -------------------------------- ### Iterative Strict Concurrency Checking Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md Gradually enable strict concurrency checking by starting with minimal settings and increasing them over time. This allows for manageable daily migration efforts. ```swift // Day 1: Enable strict concurrency, fix a few warnings // Build Settings → Strict Concurrency Checking = Complete // Day 2: Fix more warnings // Day 3: Revert to minimal checking if needed // Build Settings → Strict Concurrency Checking = Minimal ``` -------------------------------- ### Migrate XCTest Expectations to Swift Testing Confirmations Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/testing.md Illustrates how to replace XCTest's expectation-based asynchronous testing with Swift Testing's confirmation-based approach, using a closure to signal completion. ```swift // XCTest let expectation = expectation(description: "Done") doWork { expectation.fulfill() } await fulfillment(of: [expectation]) // Swift Testing await confirmation { confirm in await doWork { confirm() } } ``` -------------------------------- ### Create Async Wrapper for Closure API Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md Provide async/await wrappers for existing closure-based APIs to allow gradual adoption. This enables colleagues to use async/await immediately and tests to be updated first. ```swift // Original closure-based API @available(*, deprecated, renamed: "fetchImage(urlRequest:)", message: "Consider using the async/await alternative.") func fetchImage(urlRequest: URLRequest, completion: @escaping @Sendable (Result) -> Void) { // ... existing implementation } // New async wrapper func fetchImage(urlRequest: URLRequest) async throws -> UIImage { return try await withCheckedThrowingContinuation { continuation in fetchImage(urlRequest: urlRequest) { result in continuation.resume(with: result) } } } ``` -------------------------------- ### Chain Async Sequences Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md Concatenates two asynchronous sequences, emitting all values from the first sequence before starting the second. This is useful for sequential loading, such as loading from a cache before fetching from a network. ```swift import AsyncAlgorithms struct ArticlePaginator { func loadAllArticles() -> AsyncStream<[Article]> { AsyncStream { continuation in Task { var page = 1 var hasMore = true while hasMore { let articles = try await fetchPage(page: page) continuation.yield(articles) hasMore = articles.count == 20 page += 1 } continuation.finish() } } } } // Usage: Chain cache + network for await articles in loadFromCacheStream().chain(loadFromNetworkStream()) { display(articles) } ``` -------------------------------- ### Mixed Execution Pattern Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-await-basics.md Combine sequential and parallel execution for efficiency. Fetch initial data sequentially, then launch dependent tasks in parallel using `async let`. ```swift // Fetch user first (required for next step) let user = try await fetchUser(id: 1) // Then fetch related data in parallel async let posts = fetchPosts(userId: user.id) async let followers = fetchFollowers(userId: user.id) async let following = fetchFollowing(userId: user.id) let profile = Profile( user: user, posts: try await posts, followers: try await followers, following: try await following ) ``` -------------------------------- ### Typed Errors with Async/Await Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-await-basics.md Define specific error types for your asynchronous functions to improve API contracts and caller handling. This example shows how to catch and rethrow specific errors. ```swift enum NetworkError: Error { case invalidResponse case decodingFailed(DecodingError) case requestFailed(URLError) } func fetchData() async throws(NetworkError) -> Data { do { let (data, _) = try await URLSession.shared.data(from: url) return data } catch let error as URLError { throw .requestFailed(error) } catch { throw .invalidResponse } } ``` -------------------------------- ### Defining and Using Custom Global Actors Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/actors.md Illustrates how to define a custom global actor for specific tasks like image processing and apply it to classes and functions to serialize their execution. ```swift @globalActor actor ImageProcessing { static let shared = ImageProcessing() private init() {} // Prevent duplicate instances } @ImageProcessing final class ImageCache { var images: [URL: Data] = [:] } @ImageProcessing func applyFilter(_ image: UIImage) -> UIImage { // All image processing serialized } ``` -------------------------------- ### Actor Reentrancy Example Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/threading.md Demonstrates a reentrancy bug where a concurrent deposit modifies the balance unexpectedly due to suspension during logging. This occurs because another task can execute between suspension points. ```swift actor BankAccount { private var balance: Int = 0 func deposit(amount: Int) async { balance += amount print("Balance: \(balance)") await logTransaction(amount) // ⚠️ Suspension point balance += 10 // Bonus print("After bonus: \(balance)") } func logTransaction(_ amount: Int) async { try? await Task.sleep(for: .seconds(1)) } } // Two concurrent deposits async let _ = account.deposit(amount: 100) async let _ = account.deposit(amount: 100) // Unexpected: 100 → 200 → 210 → 220 // Expected: 100 → 110 → 210 → 220 ``` -------------------------------- ### Sequential Execution of Async Operations in Swift Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-await-basics.md Asynchronous operations marked with `await` execute sequentially. Each operation starts only after the preceding one has completed, ensuring a predictable top-to-bottom execution order. ```swift let first = try await fetchData(1) // Waits for completion let second = try await fetchData(2) // Starts after first completes let third = try await fetchData(3) // Starts after second completes ``` -------------------------------- ### Correct Task Isolation: Inheriting Main Actor Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/SKILL.md Shows the correct way to handle tasks where the synchronous prefix includes main-actor-required work, thus inheriting the main actor isolation. ```swift Task { print("debug") // trivial, non-main — rides along self.isLoading = true // needs @MainActor, before any await await fetchData() } ``` -------------------------------- ### Structured Tasks with async let Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/tasks.md Launch concurrent operations using `async let` for structured concurrency. Results are automatically awaited when accessed, and cancellation is inherited from the parent task. ```swift // async let async let data1 = fetch(1) async let data2 = fetch(2) let results = await [data1, data2] ``` -------------------------------- ### Handling SendableMetatype Error with Isolated Conformances Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/actors.md When an isolated conformance to a protocol is required, it cannot satisfy a 'SendableMetatype' requirement. This example shows the error and provides a fix by making the protocol requirement non-isolated. ```swift protocol P { static func doSomething() } func doSomethingStatic(_ type: T.Type) { } @MainActor class C { } extension C: @MainActor P { static func doSomething() { } } @MainActor func test(c: C) { doSomethingStatic(C.self) // ❌ main actor-isolated conformance of 'C' to 'P' cannot satisfy // conformance requirement for a 'Sendable' type parameter } ``` ```swift @MainActor class C: P { nonisolated static func doSomething() { } // ✅ Non-isolated requirement on a non-isolated conformance } ``` -------------------------------- ### Debounced Search Implementation Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/tasks.md Provides a practical example of using Task.sleep() for debouncing user input in a search function. It includes error handling for cancellation, which occurs if the user types rapidly. ```swift func search(_ query: String) async { guard !query.isEmpty else { searchResults = allResults return } do { try await Task.sleep(for: .milliseconds(500)) searchResults = allResults.filter { $0.contains(query) } } catch { // Canceled (user kept typing) } } // In SwiftUI .task(id: searchQuery) { await searcher.search(searchQuery) } ``` -------------------------------- ### Migrate XCTest to Swift Testing Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/testing.md Shows the transformation of a basic XCTest class and test method into the equivalent structure using Swift Testing's @Suite and @Test annotations. ```swift // XCTest final class MyTests: XCTestCase { func testExample() async { XCTAssertEqual(value, expected) } } // Swift Testing @Suite struct MyTests { @Test func example() async { #expect(value == expected) } } ``` -------------------------------- ### Main Actor Isolation Inheritance Example Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/threading.md Illustrates how `@MainActor` functions maintain their isolation. When an `await` call switches to a background task, the execution correctly returns to the main thread afterward. ```swift @MainActor func updateUI() { print("Main thread: \(Thread.current)") await backgroundTask() // Switches to background print("Back on main: \(Thread.current)") // Returns to main } func backgroundTask() async { print("Background: \(Thread.current)") } ``` -------------------------------- ### Debounce Operator Example: ArticleSearcher Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md Demonstrates using the `debounce` operator to wait for a period of inactivity before processing search queries. This prevents excessive API calls for rapid user input. ```swift import AsyncAlgorithms @Observable final class ArticleSearcher { @MainActor private(set) var results: [Article] = [] private var searchQueryContinuation: AsyncStream.Continuation? private lazy var searchQueryStream: AsyncStream = { AsyncStream { continuation in searchQueryContinuation = continuation } }() func search(_ query: String) { searchQueryContinuation?.yield(query) } func startDebouncedSearch() { Task { @MainActor in for await query in searchQueryStream.debounce(for: .milliseconds(500)) { self.results = [] self.results = await APIClient.searchArticles(query) } } } } ``` -------------------------------- ### Optimize Task Suspensions (Before) Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/performance.md Shows a task with two suspensions: one for background work and another for updating the main actor. This can be optimized. ```swift // Before: Two suspensions Task { let data = await generate() // Suspension 1 self.items.append(data) // Suspension 2 (back to main) } ``` -------------------------------- ### Reduce Suspension by Using Synchronous Methods Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/performance.md Shows how to eliminate unnecessary suspension points by converting an `async` method to a synchronous one if it doesn't require suspension. This improves performance by avoiding context switches. ```swift // ❌ Unnecessary async private func scale(_ image: CGImage) async { } func process(_ image: CGImage) async { let scaled = await scale(image) // Suspension point } // ✅ Synchronous helper private func scale(_ image: CGImage) { } func process(_ image: CGImage) async { let scaled = scale(image) // No suspension } ``` -------------------------------- ### Combine Merge vs. AsyncAlgorithms Merge + TaskGroup Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md Compares Combine's publisher merging with AsyncAlgorithms' sequence merging. For parallel execution, TaskGroup is recommended over flatMap. State updates can leverage @MainActor instead of .receive(on:). ```swift import Combine final class MultiSourceLoader: ObservableObject { @Published private(set) var items: [Item] = [] private var cancellables = Set() func loadFromAllSources() { let source1 = APIClient.fetchItems(from: .source1) let source2 = APIClient.fetchItems(from: .source2) let source3 = APIClient.fetchItems(from: .source3) Publishers.Merge3(source1, source2, source3) .flatMap { items in Just(items) .delay(for: .seconds(0.1), scheduler: DispatchQueue.main) } .scan([]) { accumulated, new in accumulated + new } .receive(on: DispatchQueue.main) .assign(to: &$items) .store(in: &cancellables) } } ``` ```swift import AsyncAlgorithms @Observable final class MultiSourceLoader { @MainActor private(set) var items: [Item] = [] func loadFromAllSources() async { let sources = [ APIClient.fetchItems(from: .source1), APIClient.fetchItems(from: .source2), APIClient.fetchItems(from: .source3) ] Task { @MainActor in for await stream in sources.map { $0.values }.merge() { for await newItems in stream { self.items.append(contentsOf: newItems) } } } } // Alternative: Using TaskGroup for parallel execution func loadFromAllSourcesParallel() async { await withTaskGroup(of: [Item].self) { group in group.addTask { await APIClient.fetchItems(from: .source1) } group.addTask { await APIClient.fetchItems(from: .source2) } group.addTask { await APIClient.fetchItems(from: .source3) } for await newItems in group { await MainActor.run { self.items.append(contentsOf: newItems) } } } } } ``` -------------------------------- ### Enable Core Data Concurrency Debugging Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/core-data.md Use the '-com.apple.CoreData.ConcurrencyDebug 1' launch argument to immediately crash on thread violations, aiding in debugging. ```bash -com.apple.CoreData.ConcurrencyDebug 1 ``` -------------------------------- ### React to Value Changes with .task Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/tasks.md Use the .task modifier to automatically cancel previous tasks and start new ones when a bound value changes. This is useful for reacting to user input or state updates. ```swift .task(id: searchQuery) { await performSearch(searchQuery) } ``` -------------------------------- ### Optimize Task Suspensions (After) Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/performance.md Presents an optimized version of the task that reduces suspensions by performing synchronous work off-main and then hopping to the main actor once. ```swift // After: One suspension Task { let data = generate() // No suspension (synchronous) await MainActor.run { self.items.append(data) // Suspension 1 (to main) } } ``` -------------------------------- ### Enable Strict Concurrency Checking with SPM Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md Configure strict concurrency checking for a target using Swift Package Manager. Start with 'Minimal' and gradually move to 'Targeted' or 'Complete' to fix errors incrementally. ```swift .target( name: "MyTarget", swiftSettings: [ .enableExperimentalFeature("StrictConcurrency=targeted") ] ) ``` -------------------------------- ### Using MainActor.assumeIsolated with Assertions Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/actors.md Shows how to use MainActor.assumeIsolated to execute code on the main thread, with a recommendation to use assertions for validation and to prefer explicit @MainActor or await MainActor.run. ```swift func methodB() { assert(Thread.isMainThread) // Validate assumption MainActor.assumeIsolated { someMainActorMethod() } } ``` -------------------------------- ### Error Handling with Mutex Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/actors.md Illustrates how to handle errors within a Mutex's critical section using `withLock`. This example shows a guarded decrement operation that throws an error if the count reaches zero. ```swift func decrement() throws { try count.withLock { count in guard count > 0 else { throw Error.reachedZero } count -= 1 } } ``` -------------------------------- ### AsyncStream for File System Monitoring Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-sequences.md Creates an AsyncStream to monitor a directory for file system changes. It uses DispatchSource to capture write events and yields a FileEvent. ```swift func watchDirectory(_ path: String) -> AsyncStream { AsyncStream(bufferingPolicy: .bufferingNewest(1)) { continuation in let source = DispatchSource.makeFileSystemObjectSource( fileDescriptor: fd, eventMask: .write, queue: .main ) source.setEventHandler { continuation.yield(.fileChanged(path)) } continuation.onTermination = { _ in source.cancel() } source.resume() } } ``` -------------------------------- ### Task Captures Self Strongly Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/memory-management.md Tasks capture variables and references like closures. This example shows a strong capture of `self` within a Task, which can lead to retain cycles if the Task is owned by `self`. ```swift Task { self.doWork() // ⚠️ Strong capture of self } ``` -------------------------------- ### Maintain Smooth UI with Async Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/performance.md Use async functions for background work to prevent UI freezes, even if the total execution time is slightly longer. Smooth animations are perceived as faster by users. ```swift // 80ms on main thread, but animation stutters @MainActor func process() { heavyWork() // Freezes UI for 1 frame } // 100ms total, but smooth UI @MainActor func process() async { await backgroundWork() // UI stays responsive } ``` -------------------------------- ### Using Continuations for Unstructured Tasks Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/testing.md Employ `withCheckedContinuation` when testing code that spawns unstructured tasks, ensuring the task completes before proceeding. ```swift @Test @MainActor func searchTaskCompletes() async { let searcher = ArticleSearcher() await withCheckedContinuation { continuation in _ = withObservationTracking { searcher.results } onChange: { continuation.resume() } searcher.startSearchTask("swift") } #expect(searcher.results.count > 0) } ``` -------------------------------- ### AsyncStream with BufferingNewest(0) Policy Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-sequences.md The .bufferingNewest(0) policy discards all values yielded before the consumer starts iterating. Only values yielded after iteration begins are received. This is suitable for real-time updates where past values are irrelevant. ```swift let stream = AsyncStream(bufferingPolicy: .bufferingNewest(0)) { continuation in continuation.yield(1) // Discarded Task { try await Task.sleep(for: .seconds(2)) continuation.yield(2) // Received continuation.finish() } } try await Task.sleep(for: .seconds(1)) for await value in stream { print(value) // Prints only: 2 } ``` -------------------------------- ### Delayed Retry with MainActor Isolation (Avoidable Wait) Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/performance.md Starting a delayed retry task on `@MainActor` can introduce an unnecessary executor wait before `Task.sleep`. This is especially true if scheduled from another executor or when the main actor is busy. ```swift // ❌ Can wait for MainActor, then suspend immediately registrationRetryTask = Task { @MainActor [weak self] in try? await Task.sleep(for: .milliseconds(100)) guard let self else { return } self.registrationRetryTask = nil self.updateConnectedTargetWindow() } ``` -------------------------------- ### AsyncThrowingStream for Progress Reporting Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-sequences.md Implements an AsyncThrowingStream to report download progress and completion. It yields progress updates and then the final data upon successful download. ```swift func download(_ url: URL) -> AsyncThrowingStream { AsyncThrowingStream { continuation in Task { do { var progress: Double = 0 while progress < 1.0 { progress += 0.1 continuation.yield(.progress(progress)) try await Task.sleep(for: .milliseconds(100)) } let data = try await URLSession.shared.data(from: url).0 continuation.yield(.completed(data)) continuation.finish() } catch { continuation.finish(throwing: error) } } } } ``` -------------------------------- ### Simple Async Test with Swift Testing Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/testing.md Use for basic asynchronous tests with Swift Testing. It utilizes the `@Test` macro and `#expect` for assertions. ```swift @Test @MainActor func emptyQuery() async { let searcher = ArticleSearcher() await searcher.search("") #expect(searcher.results == ArticleSearcher.allArticles) } ``` -------------------------------- ### Migrate Bank Account to Actor Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/sendable.md Shows the recommended migration strategy for mutable state: use an actor. Actors provide automatic isolation and thread safety. ```swift actor BankAccount { private var balance: Int = 0 func deposit(amount: Int) { balance += amount } func getBalance() -> Int { balance } } ``` -------------------------------- ### Handling Race Conditions in Tests Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/testing.md This example demonstrates a common race condition where a task might complete before a state check, leading to flaky tests. The issue arises when checking `isLoading` before the fetch task has a chance to update the state. ```swift @Test @MainActor func isLoadingState() async throws { let fetcher = ImageFetcher() let task = Task { try await fetcher.fetch(url) } // ❌ Flaky - may pass or fail #expect(fetcher.isLoading == true) try await task.value #expect(fetcher.isLoading == false) } ``` -------------------------------- ### Async Let vs Task Group Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/tasks.md Compares `async let` for a fixed number of parallel tasks with `TaskGroup` for dynamic, loop-based parallel work. Task groups offer manual cancellation control. ```swift // async let: Known task count async let user = fetchUser() async let settings = fetchSettings() let profile = Profile(user: await user, settings: await settings) ``` ```swift // TaskGroup: Dynamic task count await withTaskGroup(of: Image.self) { group in for url in urls { group.addTask { await download(url) } } } ``` -------------------------------- ### Migrate Combine Publisher to Standard Library Notifications Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/migration.md Replaces Combine's publisher for `NotificationCenter` events with the standard library's `notifications(named:)` async stream. This approach is suitable for observing system notifications. ```swift import Combine final class NotificationObserver: ObservableObject { @Published private(set) var notifications: [AppNotification] = [] private var cancellables = Set() init() { NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification) .compactMap { notification in notification.object as? AppNotification } .receive(on: DispatchQueue.main) .assign(to: &$notifications) } } ``` ```swift @Observable final class NotificationObserver { @MainActor private(set) var notifications: [AppNotification] = [] func startObserving() { Task { for await notification in NotificationCenter.default.notifications(named: UIApplication.didBecomeActiveNotification) { if let appNotification = notification.object as? AppNotification { notifications.append(appNotification) } } } } } ``` -------------------------------- ### Import AsyncAlgorithms Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/async-algorithms.md The necessary import statement to use the AsyncAlgorithms library in your Swift code. ```swift import AsyncAlgorithms ``` -------------------------------- ### Set Task Priority Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/tasks.md Shows how to explicitly set the priority for a new task when creating it. Tasks created without an explicit priority inherit from their parent. ```swift Task(priority: .background) { await prefetchData() } ``` -------------------------------- ### Nonisolated Async Function - New Behavior (Inheritance) Source: https://github.com/avdlee/swift-concurrency-agent-skill/blob/main/swift-concurrency/references/threading.md Demonstrates the new behavior in Swift 6.2 where nonisolated async functions inherit the caller's isolation by default. This example shows a `NotSendable` object's method being called from `@MainActor`, executing on the main thread. ```swift class NotSendable { func performAsync() async { print(Thread.current) } } @MainActor func caller() async { let obj = NotSendable() await obj.performAsync() // Old: Background thread // New: Main thread (inherits @MainActor) } ```