# How to Resolve Actor Isolation Warnings in Swift Concurrency: A Complete Guide

> Resolve Swift Concurrency actor isolation warnings with @MainActor, nonisolated, and @concurrent. Understand unsafe cross-actor access and ensure safe execution contexts in this complete guide.

- Repository: [Thomas Ricouard/Skills](https://github.com/Dimillian/Skills)
- Tags: how-to-guide
- Published: 2026-04-01

---

**Actor isolation warnings indicate unsafe cross-actor boundary access and are resolved by strategically applying `@MainActor` annotations, isolating protocol conformances, or leveraging `nonisolated` and `@concurrent` markers based on execution context.**

Actor isolation warnings surface when the Swift compiler detects potential data races across actor boundaries, such as accessing `@MainActor` state from non-isolated contexts. In Swift 6.2, the **Approachable Concurrency** model introduces default actor isolation that automatically protects UI-bound types, yet developers must still manually resolve warnings when code intentionally executes off the main actor or exposes isolated types through protocols. This guide draws from the **Dimillian/Skills** repository's Swift Concurrency Expert skill to provide concrete resolution strategies backed by source code analysis.

## Understanding Actor Isolation Warnings

Actor isolation warnings occur when the compiler identifies code that may cross actor boundaries unsafely. These diagnostics prevent data races by enforcing that mutable state is only accessed from the isolated context that owns it.

The Swift concurrency model uses several key annotations to control isolation:

- **@MainActor**: Guarantees the annotated type or function runs on the main thread. Typical warning: *"Calling main-actor-isolated property from a non-isolated context"*

- **actor**: Provides its own isolated mutable state. Typical warning: *"Sending actor-isolated value to a non-isolated async function"*

- **nonisolated**: Explicitly opts out of isolation; only safe for thread-safe value data. Typical warning: *"Non-isolated type accesses main-actor state"*

- **@concurrent** (Swift 6.2+): Forces an async function to run on the global concurrent executor. Typical warning: *"Potential data race because function stays on caller's actor"*

- **Sendable**: Marks a value as safe to cross actor boundaries. Typical warning: *"Closure is not Sendable when capturing @MainActor state"*

## Common Triggers for Actor Isolation Warnings

According to the concurrency expert documentation in [`swift-concurrency-expert/SKILL.md`](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/SKILL.md), three patterns commonly trigger these diagnostics:

1. **Accessing `@MainActor` state inside a `Sendable` closure**: Swift flags this because the closure may execute on a background thread while capturing main-actor isolated `self`.

2. **Protocol conformance on a main-actor type without isolation**: When a `@MainActor` class conforms to a protocol but the conformance itself is not isolated, the compiler cannot guarantee callers remain on the main actor.

3. **Global or static mutable state without actor protection**: Unprotected mutable state accessible from multiple contexts triggers data-race diagnostics.

## Step-by-Step Resolution Strategy

Follow this workflow from the Dimillian/Skills repository to systematically eliminate warnings:

1. **Confirm the project's concurrency mode**: Check Xcode Build Settings for *Swift Language Version ≥ 6.2* and verify *Default Actor Isolation / Main Actor by default* is enabled, or inspect [`Package.swift`](https://github.com/Dimillian/Skills/blob/main/Package.swift) Swift settings. Reference the [Approachable Concurrency guide](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/references/approachable-concurrency.md) for configuration details.

2. **Identify the offending symbol**: Note the specific line numbers and symbols mentioned in the compiler diagnostic to understand which actor boundary is being crossed.

3. **Apply the smallest safe annotation**:
   - **UI-bound types**: Annotate the entire type with `@MainActor` (or rely on default-by-default mode in Swift 6.2).
   - **Protocol conformance**: Scope the conformance to `@MainActor` using `extension Foo: @MainActor SomeProtocol`.
   - **Sendable closure capture**: Capture a value copy instead of `self`, or make the closure non-Sendable only when deliberately detaching work with `Task.detached`.
   - **Background-heavy work**: Move heavy code to a `nonisolated` async function or mark it `@concurrent`.

4. **Validate**: Rebuild the project; all actor-isolation warnings should disappear. Run the test suite to catch runtime regressions, particularly in UI state changes.

5. **Iterate**: Address new warnings that emerge from changed isolation boundaries by repeating steps 2-4.

## Practical Code Examples

The following examples from [`swift-concurrency-expert/SKILL.md`](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/SKILL.md) demonstrate specific fixes for common isolation violations.

### Annotating UI-Bound Types with @MainActor

When a view model lacks isolation but manipulates UI state, apply `@MainActor` to the entire class declaration.

**Before (generates warning)**:

```swift
// ViewModel is accessed from the main thread but has no actor isolation
class ViewModel: ObservableObject {
    @Published var title: String = ""
    func load() { title = "Loaded" }
}

```

**After (warning resolved)**:

```swift
@MainActor
class ViewModel: ObservableObject {
    @Published var title: String = ""
    func load() { title = "Loaded" }
}

```

*Source: [[`SKILL.md`](https://github.com/Dimillian/Skills/blob/main/SKILL.md) lines 40-56](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/SKILL.md#L40-L56)*

### Isolating Protocol Conformances

Protocol methods that access main-actor state require explicit isolation on the conformance extension.

**Before (generates warning)**:

```swift
@MainActor
class Foo: SomeProtocol {
    func protocolMethod() { /* accesses main-actor state */ }
}

```

**After (warning resolved)**:

```swift
@MainActor
class Foo { /* … */ }

@MainActor
extension Foo: SomeProtocol {
    func protocolMethod() { /* safely accesses main-actor state */ }
}

```

*Source: [[`SKILL.md`](https://github.com/Dimillian/Skills/blob/main/SKILL.md) lines 59-74](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/SKILL.md#L59-L74)*

### Handling Sendable Closures Without Capturing self

Avoid capturing `self` in Sendable closures by extracting values before the async boundary.

**Before (generates warning)**:

```swift
Task {
    await someModel.doWork { self.title = "Done" }   // `self` captured in Sendable closure
}

```

**After (warning resolved)**:

```swift
Task {
    let titleCopy = self.title
    await someModel.doWork { titleCopy = "Done" }   // safe copy, no main-actor capture
}

```

*Source: [[`swiftui-concurrency-tour-wwdc.md`](https://github.com/Dimillian/Skills/blob/main/swiftui-concurrency-tour-wwdc.md) lines 19-22](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md#L19-L22)*

### Moving Heavy Work to Background with @concurrent

Use `@concurrent` to force execution onto the global concurrent executor when processing large datasets off the main thread.

**Before (runs on main actor)**:

```swift
@MainActor
func processData(_ input: [Int]) -> [Int] {
    input.map { heavyTransform($0) }   // runs on main thread → UI hitch
}

```

**After (concurrent execution)**:

```swift
@concurrent
func processData(_ input: [Int]) async -> [Int] {
    await Task.detached {
        input.map { heavyTransform($0) }
    }.value
}

```

*Source: [[`SKILL.md`](https://github.com/Dimillian/Skills/blob/main/SKILL.md) lines 77-99](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/SKILL.md#L77-L99)*

## Source File References in Dimillian/Skills

The resolution strategies above derive from these specific files in the repository:

- **[`swift-concurrency-expert/SKILL.md`](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/SKILL.md)**: Defines the complete workflow for triaging and fixing Swift concurrency issues, including the step-by-step isolation resolution process and code examples at lines 40-99.

- **[`swift-concurrency-expert/references/approachable-concurrency.md`](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/references/approachable-concurrency.md)**: Documents the default-by-default actor isolation mode introduced in Swift 6.2, explaining detection mechanisms and fix application.

- **[`swift-concurrency-expert/references/swift-6-2-concurrency.md`](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/references/swift-6-2-concurrency.md)**: Details language changes in Swift 6.2 affecting actor isolation semantics and data-race diagnostics.

- **[`swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md`](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md)**: Provides SwiftUI-specific guidance on off-main-thread execution contexts and Sendable closure handling.

## Summary

- **Actor isolation warnings** prevent data races by enforcing strict boundaries between the main actor, custom actors, and non-isolated contexts.

- **`@MainActor`** applied to types eliminates individual member annotations for UI-bound objects.

- **Protocol conformances** must be explicitly isolated using `@MainActor` extensions when the conforming type contains main-actor state.

- **`@concurrent`** (Swift 6.2+) explicitly moves heavy computational work to the global concurrent executor, satisfying the compiler's data-race analysis.

- **Sendable closures** should capture value copies rather than `self` references to avoid crossing actor boundaries unsafely.

## Frequently Asked Questions

### What causes actor isolation warnings in Swift 6.2?

Actor isolation warnings in Swift 6.2 typically occur when **Approachable Concurrency** detects that code accesses `@MainActor` state from a non-isolated context, or when a `Sendable` closure captures isolated values that may execute on background threads. The compiler emits these warnings to prevent potential data races at compile time rather than allowing runtime crashes.

### When should I use `@concurrent` versus `nonisolated`?

Use **`@concurrent`** for async functions that intentionally perform heavy work on the global concurrent executor while still potentially returning to the caller's isolation context. Use **`nonisolated`** only for synchronous functions or properties that access immutable, thread-safe value types (like constants or value-type data structures) that do not require actor protection.

### How do I fix Sendable closure warnings when I need to update UI?

Extract the required values from `self` before entering the async context. Capture a copy of the data rather than the `self` reference itself, or use `MainActor.run` to hop back to the main actor for updates. According to the Dimillian/Skills SwiftUI concurrency guidelines, capturing `let` constants instead of `self` satisfies the Sendable requirement while maintaining thread safety.

### Where does Dimillian/Skills document these resolution patterns?

The **Dimillian/Skills** repository centralizes these patterns in [`swift-concurrency-expert/SKILL.md`](https://github.com/Dimillian/Skills/blob/main/swift-concurrency-expert/SKILL.md), with supplementary context in [`references/approachable-concurrency.md`](https://github.com/Dimillian/Skills/blob/main/references/approachable-concurrency.md) for Swift 6.2 default isolation, [`references/swift-6-2-concurrency.md`](https://github.com/Dimillian/Skills/blob/main/references/swift-6-2-concurrency.md) for language changes, and [`references/swiftui-concurrency-tour-wwdc.md`](https://github.com/Dimillian/Skills/blob/main/references/swiftui-concurrency-tour-wwdc.md) for UI-specific concurrency scenarios.