---
title: Mastering Swift 6 Strict Concurrency: Actor Isolation, Sendable Protocol, and Eliminating Data Races in Production
publishedAt: 2026-08-29
summary: An architectural guide to Swift 6 strict concurrency checking, actor isolation semantics, Sendable conformance, region-based isolation (SE-0414), and systematic migration strategies for production iOS and macOS codebases.
---

# Mastering Swift 6 Strict Concurrency: Actor Isolation, Sendable Protocol, and Eliminating Data Races in Production

> **Executive Summary (TL;DR):** Swift 6 establishes compile-time data race safety as a language-level guarantee across Apple platforms and Linux servers. By replacing manual synchronization primitives (such as GCD queues, locks, and condition variables) with static isolation checking, the `Sendable` type system, and region-based isolation analysis ([SE-0414](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0414-region-based-isolation.md)), the Swift 6 compiler flags potential concurrency violations during compilation. This architectural guide examines the cooperative runtime model, dissects actor reentrancy hazards and mitigation patterns, details standard library synchronization primitives ([`Synchronization.Mutex`](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0433-mutex.md)), and outlines a phased migration path for production systems.

---

## 1. The Paradigm Shift: From Runtime Synchronization to Static Isolation

Swift 6 transitions concurrency safety from error-prone runtime discipline to verifiable compile-time guarantees. In legacy systems, concurrent access bugs were only caught reactively through crash logs or Thread Sanitizer sweeps. Under the Swift 6 language mode, isolation domains and value-transfer boundaries are statically enforced by the compiler before code is deployed.

```
+-----------------------------------------------------------------------------------+
| Legacy Concurrency (GCD / Locks)                                                 |
| [Thread 1] ───┐                                                                   |
| [Thread 2] ───┼──► [Shared Mutable State]  ──► Runtime Race Condition             |
| [Thread 3] ───┘    (Unsynchronized Access)     (Detection: Runtime TSan / Crash)  |
+-----------------------------------------------------------------------------------+
                                         │
                                         ▼ Swift 6 Language Mode
+-----------------------------------------------------------------------------------+
| Swift 6 Strict Concurrency                                                       |
| [Actor Boundary]       ──► Serial Mailbox & Cooperative Executor                  |
| [Sendable Boundary]    ──► Static verification of value transfer at build time    |
| [Region Isolation]     ──► Disconnected memory escape analysis (SE-0414)          |
+-----------------------------------------------------------------------------------+
```

For over a decade, multithreaded programming in Apple ecosystems centered on Grand Central Dispatch (`DispatchQueue`), POSIX threads, and locking primitives (`os_unfair_lock`, `NSLock`). While flexible, this approach introduced fundamental architectural liabilities:

* **Manual Synchronization Burden:** Correctness relied entirely on developer discipline. A single un-synchronized read or write across threads introduced undefined behavior, subtle memory corruption, or non-deterministic crashes.
* **Thread Sanitizer (TSan) Limitations:** Dynamic analysis tools like TSan can only flag race conditions that are actively executed during runtime test runs, leaving dormant or edge-case execution paths undetected.
* **Thread Explosion & Priority Inversion:** Unbounded creation of concurrent dispatch queues frequently led to hundreds of blocked threads competing for kernel resources, increasing context-switching overhead and triggering priority inversions.

### The Swift Concurrency Runtime Model

As documented in the official [Swift Concurrency Guide](https://www.swift.org/documentation/concurrency/), the language replaces ad-hoc thread creation with a **cooperative thread pool**. The runtime maintains a bounded pool of worker threads sized strictly to the number of available active CPU cores.

When a Swift `Task` suspends at an `await` point:
1. The underlying thread is not blocked; it yields execution control back to the cooperative scheduler.
2. The scheduler assigns other ready tasks to that worker thread.
3. When the suspended task is ready to resume, the scheduler schedules its execution context onto an available thread in the pool (or the actor's associated executor).

This cooperative execution model avoids thread explosion, but it introduces distinct isolation and reentrancy behaviors that require explicit architectural design.

---

## 2. Actor Isolation and the Reentrancy Hazard

Actors protect mutable internal state through a serial mailbox mechanism that permits only one synchronous task to execute at a time. However, actors are reentrant across suspension points (`await`), meaning their state can mutate while waiting for asynchronous operations. Robust actor architectures must guard against state invalidation by deduplicating in-flight work or re-evaluating invariants after resumption.

### How Actors Protect Mutable State

An `actor` is a reference type that encapsulates its mutable state behind a **serial message mailbox** and a dedicated executor. Only one task can execute synchronous isolated code on an actor instance at any given time.

```swift
actor UserSessionStore {
    private var activeSessions: [UUID: UserSession] = [:]
    
    func store(_ session: UserSession, for id: UUID) {
        activeSessions[id] = session
    }
    
    func retrieveSession(for id: UUID) -> UserSession? {
        return activeSessions[id]
    }
}
```

Cross-actor interactions must occur asynchronously via `await`, signaling a potential context switch to the target actor's executor:

```swift
func authenticateUser(id: UUID, store: UserSessionStore) async {
    // Execution hops to the store's serial executor
    if let session = await store.retrieveSession(for: id) {
        print("Restored session for \(session.username)")
    }
}
```

---

### Actor Reentrancy: Why `await` is a State Invalidation Hazard

A critical architectural distinction between serial dispatch queues and Swift actors is **actor reentrancy**:

* **Serial DispatchQueue:** Blocks subsequent work entirely until the current closure completes.
* **Swift Actor:** Suspends execution at every `await` point, freeing its mailbox to process other incoming calls while waiting for the asynchronous operation to complete.

If an actor assumes its internal state remains unchanged across an `await` boundary, subtle state-corruption bugs can emerge.

#### The Reentrancy Bug in an Asynchronous Cache

```swift
actor AssetPipeline {
    private var cache: [URL: Data] = [:]
    private let client: NetworkClient
    
    init(client: NetworkClient) {
        self.client = client
    }
    
    func loadAsset(from url: URL) async throws -> Data {
        // Step 1: Check in-memory state
        if let cached = cache[url] {
            return cached
        }
        
        // Hazard: Suspension Point!
        // The actor suspends. Other tasks calling loadAsset(from: url) can execute
        // and pass the cache check above before this download finishes.
        let data = try await client.download(from: url)
        
        // Step 2: Unsafe state assumption after resumption
        cache[url] = data
        return data
    }
}
```

If multiple concurrent callers request the same uncached URL, each caller passes the initial cache check, suspends at `download(from:)`, executes redundant network transfers, and sequentially overwrites the cache.

#### The Production Fix: In-Flight Task Deduplication

To resolve reentrancy hazards for expensive operations, memoize the **in-flight `Task`** synchronously before suspending:

```swift
actor AssetPipeline {
    private var cache: [URL: Data] = [:]
    private var inFlightTasks: [URL: Task<Data, Error>] = [:]
    private let client: NetworkClient
    
    init(client: NetworkClient) {
        self.client = client
    }
    
    func loadAsset(from url: URL) async throws -> Data {
        // 1. Check completed cache
        if let cached = cache[url] {
            return cached
        }
        
        // 2. Return existing in-flight task if already requested
        if let existingTask = inFlightTasks[url] {
            return try await existingTask.value
        }
        
        // 3. Register in-flight task synchronously before suspending
        let downloadTask = Task { () throws -> Data in
            return try await client.download(from: url)
        }
        
        inFlightTasks[url] = downloadTask
        
        // 4. Await completion and clean up
        do {
            let data = try await downloadTask.value
            cache[url] = data
            inFlightTasks[url] = nil
            return data
        } catch {
            inFlightTasks[url] = nil
            throw error
        }
    }
}
```

---

## 3. Fine-Grained Isolation and Modern Synchronization

Fine-grained isolation allows developers to explicitly designate which threads or contexts own specific data structures. By using `@MainActor`, `nonisolated`, and the standard library's `Synchronization.Mutex` introduced in [SE-0433](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0433-mutex.md), applications eliminate unsafe workarounds like `@unchecked Sendable`. These annotations provide precise control over main-thread UI operations and high-performance synchronous memory locks.

```
┌──────────────────────────────────────────────────────────────────────────┐
│ Swift 6 Isolation Attributes                                              │
├──────────────────────────┬───────────────────────────────────────────────┤
│ @MainActor               │ Isolates state/execution to the main thread   │
├──────────────────────────┼───────────────────────────────────────────────┤
│ nonisolated              │ Removes actor isolation for immutable/pure fn │
├──────────────────────────┼───────────────────────────────────────────────┤
│ nonisolated(unsafe)      │ Disables compiler checks on a property (SE-412│
├──────────────────────────┼───────────────────────────────────────────────┤
│ Mutex<Value> (SE-0433)   │ Standard library lock; eliminates unchecked   │
│                          │ Sendable workarounds                          │
└──────────────────────────┴───────────────────────────────────────────────┘
```

### 1. `@MainActor` and UI State Binding

`@MainActor` is a global actor that guarantees execution on the main run loop. It is essential for view models, UI updates, and binding to SwiftUI and UIKit components:

```swift
@MainActor
final class AccountViewModel: ObservableObject {
    @Published private(set) var balance: Decimal = .zero
    
    // Opt-out of main thread isolation for deterministic, pure computations
    nonisolated func formattedIdentifier(prefix: String, id: UUID) -> String {
        return "\(prefix)-\(id.uuidString.lowercased())"
    }
}
```

### 2. Eliminating `@unchecked Sendable` with `Synchronization.Mutex` (SE-0433)

In prior Swift versions, custom thread-safe classes wrapping low-level locks required `@unchecked Sendable`, completely disabling compiler validation for that type.

Swift 6 introduces the standard library `Synchronization` module ([SE-0433](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0433-mutex.md)), providing the non-copyable `Mutex<Value>` generic type. This enables safe, synchronous synchronization without bypassing compiler checks:

```swift
import Synchronization

final class ThreadSafeMetricsCollector: Sendable {
    // Mutex provides mutual exclusion without @unchecked Sendable
    private let metrics = Mutex<[String: Int]>([:])
    
    func recordEvent(_ eventName: String) {
        metrics.withLock { dict in
            dict[eventName, default: 0] += 1
        }
    }
    
    func snapshot() -> [String: Int] {
        metrics.withLock { dict in
            return dict
        }
    }
}
```

### 3. `nonisolated(unsafe)` (SE-0412)

When interfacing with global C variables, hardware registers, or legacy SDKs where `Mutex` cannot be applied, [`nonisolated(unsafe)`](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0412-strict-concurrency-for-global-variables.md) explicitly marks the variable as opted out of isolation checking. This should be restricted to low-level interop points:

```swift
// Explicit opt-out of data race checks for low-level global state
private nonisolated(unsafe) var rawHardwarePacketCounter: UInt64 = 0
```

---

## 4. Sendable Protocol, Region-Based Isolation, and the `sending` Keyword

The `Sendable` protocol defines types whose values can safely cross isolation domains without introducing data races. Swift 6 enhances this model with Region-Based Isolation ([SE-0414](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0414-region-based-isolation.md)), which uses flow-sensitive compiler analysis to allow non-`Sendable` instances to cross boundaries when provably disconnected. The `sending` parameter modifier ([SE-0430](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0430-transferring-parameters-and-results.md)) makes these cross-domain transfers explicit in function signatures.

```
                    ┌────────────────────────┐
                    │ Is the Type Sendable?  │
                    └───────────┬────────────┘
                                │
        ┌───────────────────────┴───────────────────────┐
        ▼                                               ▼
  [Value Types]                                  [Reference Types]
  • Structs (all properties Sendable)            • Actors (isolated state)
  • Enums (all associated values Sendable)       • Final classes (immutable let props)
  • Primitive scalar types                       • Types using Synchronization.Mutex
```

### What Makes a Type `Sendable`?

1. **Implicit Conformance:** Structs and enums whose stored properties conform to `Sendable` receive implicit conformance when declared `internal` or `private`.
2. **Explicit Class Sendability:** Classes can conform to `Sendable` only if they are `final`, contain exclusively immutable (`let`) `Sendable` properties, and inherit directly from `NSObject` or have no superclass.

```swift
// Safely Sendable Reference Type
public final class ConfigurationPayload: Sendable {
    public let endpoint: URL
    public let requestTimeout: TimeInterval
    
    public init(endpoint: URL, requestTimeout: TimeInterval = 30.0) {
        self.endpoint = endpoint
        self.requestTimeout = requestTimeout
    }
}
```

---

### Region-Based Isolation Analysis (SE-0414)

Prior to Swift 6, passing a non-`Sendable` type across an isolation domain produced a compilation error, even if the sending domain immediately discarded all references to that object.

Swift 6 introduces **Region-Based Isolation** ([SE-0414](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0414-region-based-isolation.md)). The compiler performs flow-sensitive escape analysis to track whether an object belongs to a disconnected memory region. If the compiler proves that no concurrent access can occur after transfer, non-`Sendable` values are allowed to cross isolation boundaries safely:

```swift
final class MutablePayload {
    var attributes: [String: String] = [:]
}

actor DataIngestionActor {
    func ingest(_ payload: MutablePayload) {
        payload.attributes["status"] = "ingested"
    }
}

func processPayload(ingestor: DataIngestionActor) async {
    let payload = MutablePayload()
    payload.attributes["source"] = "sensor_alpha"
    
    // Valid in Swift 6 under Region-Based Isolation (SE-0414):
    // 'payload' is disconnected and not accessed again in this scope.
    await ingestor.ingest(payload)
    
    // Attempting to access 'payload' here invalidates region isolation and fails compilation:
    // print(payload.attributes) 
    // ^ Error: Transfer of non-Sendable value 'payload' has race potential
}
```

### Explicit Transfer with the `sending` Keyword (SE-0430)

Swift 6 adds the `sending` parameter and result modifier ([SE-0430](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0430-transferring-parameters-and-results.md)), allowing functions to explicitly declare that a value is transferred out of its current isolation region:

```swift
func buildDisconnectedPayload(id: String) -> sending MutablePayload {
    let payload = MutablePayload()
    payload.attributes["id"] = id
    return payload // Proves the returned region is disconnected
}
```

---

## 5. Systematic Migration Strategy for Production Codebases

Migrating existing production codebases to Swift 6 strict concurrency requires a structured, multi-phase approach to avoid blocking release pipelines. Teams should first enable complete concurrency checking in audit mode to uncover diagnostic warnings across module boundaries. Legacy callback APIs can then be bridged with checked continuations, third-party libraries annotated with `@preconcurrency`, and targets converted incrementally to the Swift 6 language mode.

```
Phase 1: Diagnostic Audit   Phase 2: Modernize Callbacks   Phase 3: Swift 6 Mode
┌────────────────────────┐  ┌───────────────────────────┐  ┌────────────────────────┐
│ SWIFT_STRICT_          │  │ withCheckedContinuation   │  │ Set Language Mode = 6  │
│ CONCURRENCY = Complete │─►│ Synchronization.Mutex     │─►│ Full compile-time data │
│ (Audit Xcode warnings) │  │ @preconcurrency import    │  │ race safety enforced   │
└────────────────────────┘  └───────────────────────────┘  └────────────────────────┘
```

### Step 1: Enable Complete Checking in Build Settings

Before switching whole targets to the Swift 6 language mode, turn on complete checking under your target's **Build Settings**:

* `SWIFT_STRICT_CONCURRENCY` = `Complete`
* `-enable-upcoming-feature RegionBasedIsolation`

Resolve emitted warnings incrementally. Under the Swift 6 language mode, these warnings become hard build errors.

---

### Step 2: Bridge Legacy Callback APIs with Checked Continuations

Convert legacy closure-based asynchronous APIs to `async/await` using `withCheckedThrowingContinuation` or `withCheckedContinuation`.

> [!IMPORTANT]
> **Continuation Invariant:** The continuation **must be resumed exactly once** along every possible execution path. Resuming zero times permanently leaks the awaiting task; resuming more than once triggers an immediate runtime assertion crash in checked continuations.

```swift
// Legacy Signature:
// func fetchRemoteProfile(id: String, completion: @escaping (Result<Profile, Error>) -> Void)

func fetchRemoteProfile(id: String) async throws -> Profile {
    try await withCheckedThrowingContinuation { continuation in
        fetchRemoteProfile(id: id) { result in
            switch result {
            case .success(let profile):
                continuation.resume(returning: profile)
            case .failure(let error):
                continuation.resume(throwing: error)
            }
        }
    }
}
```

---

### Step 3: Handle Unannotated Dependencies with `@preconcurrency`

When consuming external frameworks that have not yet adopted Swift 6 annotations, use `@preconcurrency import` to downgrade diagnostics to warnings while maintaining strict checking for internal code:

```swift
// Suppresses compiler errors for unannotated types originating from LegacySDK
@preconcurrency import LegacyAnalyticsSDK

actor TelemetryService {
    private let tracker: LegacyTracker
    
    init(tracker: LegacyTracker) {
        self.tracker = tracker
    }
    
    func track(event: String) {
        tracker.logEvent(event)
    }
}
```

---

### Step 4: Verification with Xcode Thread Sanitizer (TSan)

Static checking covers Swift-isolated code, but C-library interoperability, unsafe pointers, and `@unchecked Sendable` escape hatches require dynamic validation.

To run TSan:
1. Open **Product > Scheme > Edit Scheme...** (`Cmd + <`).
2. Select **Run** or **Test**.
3. Under the **Diagnostics** tab, enable **Thread Sanitizer**.
4. Execute unit, integration, and stress tests to detect low-level synchronization faults.

---

## 6. Production Architecture: Concurrent Two-Tier Cache

A production cache engine must combine thread-safe storage, request deduplication, and main-actor UI projection without introducing race conditions or reentrancy stalls. The implementation below isolates storage within an actor, memoizes in-flight asynchronous tasks, and safely projects state updates onto a `@MainActor`-bound view model. This architecture guarantees compile-time data race safety under Swift 6 mode.

```swift
import Foundation
import SwiftUI

// MARK: - Domain Models

public struct CacheItem<T: Sendable>: Sendable {
    public let value: T
    public let expiration: Date
    
    public var isExpired: Bool {
        Date() > expiration
    }
    
    public init(value: T, expiration: Date) {
        self.value = value
        self.expiration = expiration
    }
}

// MARK: - Actor-Isolated Cache Engine

public actor PersistentCacheEngine<Key: Hashable & Sendable, Value: Sendable> {
    private var storage: [Key: CacheItem<Value>] = [:]
    private var inFlightTasks: [Key: Task<Value, Error>] = [:]
    
    public init() {}
    
    public func get(forKey key: Key) -> Value? {
        guard let item = storage[key] else { return nil }
        if item.isExpired {
            storage[key] = nil
            return nil
        }
        return item.value
    }
    
    public func set(_ value: Value, forKey key: Key, ttl: TimeInterval = 300) {
        storage[key] = CacheItem(value: value, expiration: Date().addingTimeInterval(ttl))
    }
    
    public func value(
        forKey key: Key,
        ttl: TimeInterval = 300,
        fetcher: @escaping @Sendable () async throws -> Value
    ) async throws -> Value {
        // 1. Return valid cached value if available
        if let cached = get(forKey: key) {
            return cached
        }
        
        // 2. Deduplicate concurrent requests
        if let ongoing = inFlightTasks[key] {
            return try await ongoing.value
        }
        
        // 3. Spawn and register background task
        let task = Task { () throws -> Value in
            return try await fetcher()
        }
        inFlightTasks[key] = task
        
        defer {
            inFlightTasks[key] = nil
        }
        
        do {
            let result = try await task.value
            set(result, forKey: key, ttl: ttl)
            return result
        } catch {
            throw error
        }
    }
    
    public func invalidate(forKey key: Key) {
        storage[key] = nil
        inFlightTasks[key]?.cancel()
        inFlightTasks[key] = nil
    }
    
    public func purge() {
        storage.removeAll()
        inFlightTasks.values.forEach { $0.cancel() }
        inFlightTasks.removeAll()
    }
}

// MARK: - Presentation ViewModel (@MainActor)

public struct FeedItem: Sendable, Identifiable, Codable {
    public let id: UUID
    public let headline: String
    
    public init(id: UUID = UUID(), headline: String) {
        self.id = id
        self.headline = headline
    }
}

@MainActor
public final class FeedViewModel: ObservableObject {
    @Published public private(set) var items: [FeedItem] = []
    @Published public private(set) var isLoading: Bool = false
    @Published public var errorMessage: String?
    
    private let cache: PersistentCacheEngine<String, [FeedItem]>
    
    public init(cache: PersistentCacheEngine<String, [FeedItem]> = PersistentCacheEngine()) {
        self.cache = cache
    }
    
    public func loadFeed(channelId: String) async {
        isLoading = true
        errorMessage = nil
        
        do {
            let feed = try await cache.value(forKey: channelId) {
                // Non-isolated asynchronous network retrieval
                return try await Self.fetchRemoteFeed(channelId: channelId)
            }
            self.items = feed
        } catch is CancellationError {
            // Cancellation handled cleanly without user alert
        } catch {
            self.errorMessage = error.localizedDescription
        }
        
        self.isLoading = false
    }
    
    private static func fetchRemoteFeed(channelId: String) async throws -> [FeedItem] {
        try await Task.sleep(nanoseconds: 300_000_000) // Simulated network latency
        return [
            FeedItem(headline: "Swift 6 Strict Concurrency Architecture"),
            FeedItem(headline: "Actor Isolation Patterns in Production")
        ]
    }
}
```

---

## 7. Architectural Comparison: GCD vs. Swift Concurrency

Comparing Grand Central Dispatch with Swift 6 Concurrency highlights fundamental differences in thread scheduling, race detection, and API boundaries. GCD operates on an unmanaged thread model where queues can proliferate and block underlying OS threads. Swift 6 replaces this with a cooperative, core-matched thread pool and compile-time isolation checking that eliminates data races at build time.

| Architectural Dimension | Grand Central Dispatch (GCD) | Swift 5 Concurrency Mode | Swift 6 Strict Concurrency |
| :--- | :--- | :--- | :--- |
| **Data Race Detection** | Runtime only (TSan / Crash diagnostics) | Opt-in compile-time warnings (`targeted` / `complete`) | **Enforced static isolation checking (Build errors)** |
| **State Synchronization** | Manual (`os_unfair_lock`, dispatch barriers) | Actors & Tasks (Permissive `Sendable` checking) | **Actor Mailbox + `Synchronization.Mutex` ([SE-0433](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0433-mutex.md))** |
| **Cross-Domain Value Transfer** | Unchecked pointer/reference sharing | Emits warnings on non-`Sendable` capture | **Strict Sendable + Region-Based Isolation ([SE-0414](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0414-region-based-isolation.md))** |
| **Main Thread Safety** | `DispatchQueue.main.async` conventions | `@MainActor` attribute | **Compile-time enforced `@MainActor` boundary** |
| **Thread Pool Model** | Unbounded threads (Risk of thread explosion) | Cooperative thread pool | **Bounded cooperative thread pool (Core-count matched)** |

---

## 8. Frequently Asked Questions (FAQ)

Understanding nuanced edge cases in Swift 6 concurrency prevents common architectural anti-patterns and performance traps. The questions below clarify distinctions between closure annotations, synchronization primitives, and deadlock avoidance in production systems. Reviewing these architectural trade-offs helps teams design reliable concurrency boundaries.

### What is the difference between an `@escaping` closure and a `@Sendable` closure?
An `@escaping` closure simply outlives the scope of the function to which it is passed, but it may execute within the exact same isolation domain or thread. A `@Sendable` closure is statically verified by the compiler as safe to cross concurrent execution domains. In Swift 6, `@Sendable` closures cannot capture mutable local variables by reference and require all captured values to be `Sendable` or provably disconnected via region-based isolation.

### When should I use `Synchronization.Mutex` instead of an `actor`?
Use an `actor` when you need asynchronous message queuing, cooperation with async runtimes, or when operations involve asynchronous I/O (`await`). Use `Synchronization.Mutex` ([SE-0433](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0433-mutex.md)) when synchronizing low-latency, synchronous in-memory state mutations across threads where introducing `async/await` overhead or actor context switches is undesirable or unnecessary.

### Does Swift 6 Actor isolation prevent deadlocks?
Swift actors prevent **data races**, but they do not automatically prevent all high-level **deadlocks** or **actor reentrancy bugs**. For example, if Actor A synchronously awaits Actor B, and Actor B concurrently awaits Actor A within a non-yielding cycle, task execution will stall. Maintain clear, unidirectional dependency graphs between actors to prevent circular dependencies.

---

### About the Author
**Furkan Çetinkaya** is a Mobile-focused Software Developer specializing in React Native, native bridge integrations (Kotlin & Swift), and supporting backend services. Experienced in maintaining high-impact mobile applications and developer SDKs.
- [GitHub](https://github.com/cetfu)
- [LinkedIn](https://www.linkedin.com/in/cetfu)