mcpField
A
axiom-assume-isolated

axiom-assume-isolated

github.com/charleswiltgen开发1.2k168 次安装今天更新
代码仓库

关于 axiom-assume-isolated

介绍 Swift 中的 `assumeIsolated`,用于确认当前隔离域正确时同步访问 Actor 隔离状态。内容说明适用场景、错误隔离时的崩溃行为,以及 `await` 等替代方式。

主要功能

  1. 01同步访问 Actor 隔离状态
  2. 02在测试中使用 MainActor.assumeIsolated
  3. 03将 assumeIsolated 用于委托回调
  4. 04了解隔离检查与崩溃行为
  5. 05隔离不确定时选择异步替代方式

适用场景

  1. 01同步测试 MainActor 代码
  2. 02处理文档保证在主线程执行的委托回调
  3. 03避免同步代码中的异步切换
  4. 04检查不安全的隔离假设

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/charleswiltgen/axiom --skill axiom-assume-isolated

安装后在 Claude Code 中输入/axiom-assume-isolated确认已加载。

详细介绍

assumeIsolated —— 同步访问 Actor 隔离状态

当你确定当前已处于正确的隔离域时,同步访问 Actor 隔离状态。

使用时机

✅ 适用于:

  • 同步测试 MainActor 代码(避免 Task 开销)
  • 文档注明在主线程运行的旧式委托回调
  • 需要避免 async 跳转开销的性能关键代码
  • 回调保证在特定 Actor 上运行的协议一致性实现

❌ 不适用于:

  • 不确定当前的隔离状态时(改用 await)
  • 已处于 async 上下文中(你已具备隔离状态)
  • 需要跨 Actor 调用时(改用 async)
  • 回调来源未知或不可信时

API 参考

MainActor.assumeIsolated
static func assumeIsolated<T>(
    _ operation: @MainActor () throws -> T,
    file: StaticString = #fileID,
    line: UInt = #line
) rethrows -> T where T: Sendable

行为:同步执行。如果不在 MainActor 的串行执行器上,则崩溃。

自定义 Actor 的 assumeIsolated
func assumeIsolated<T>(
    _ operation: (isolated Self) throws -> T,
    file: StaticString = #fileID,
    line: UInt = #line
) rethrows -> T where T: Sendable

Task 与 assumeIsolated

方面Task { @MainActor in }MainActor.assumeIsolated
时机延迟执行(下一个运行循环)同步执行(内联)
Async 支持支持(可使用 await)不支持(仅限同步)
上下文可在任意上下文中使用必须是同步函数
失败方式仍会运行如果隔离状态不正确则崩溃
使用场景启动异步工作验证并访问隔离状态

模式

模式 1:测试 MainActor 代码
@Test func viewModelUpdates() {
    MainActor.assumeIsolated {
        let vm = ViewModel()
        vm.update()
        #expect(vm.state == .updated)
    }
}
模式 2:旧式委托回调

摘自 WWDC 2024-10169 —— 文档保证回调在主线程上执行时:

@MainActor
class LocationDelegate: NSObject, CLLocationManagerDelegate {
    var location: CLLocation?

    // CLLocationManager created on main thread delivers callbacks on main thread
    nonisolated func locationManager(
        _ manager: CLLocationManager,
        didUpdateLocations locations: [CLLocation]
    ) {
        MainActor.assumeIsolated {
            self.location = locations.last
        }
    }
}
模式 3:@preconcurrency 简写

@preconcurrency 是等效的简写形式,会自动包装在 assumeIsolated 中:

// ❌ Manual approach (verbose)
extension MyClass: SomeDelegate {
    nonisolated func callback() {
        MainActor.assumeIsolated {
            self.updateUI()
        }
    }
}

// ✅ Using @preconcurrency (equivalent, cleaner)
extension MyClass: @preconcurrency SomeDelegate {
    func callback() {
        self.updateUI()  // Compiler wraps in assumeIsolated
    }
}

协议添加隔离状态后:@preconcurrency 将不再需要,编译器也会发出警告。

模式 4:在 assumeIsolated 前检查线程

当调用方上下文未知时(例如,在库代码中):

func getView() -> UIView {
    if Thread.isMainThread {
        return createHostingViewOnMain()
    } else {
        return DispatchQueue.main.sync {
            createHostingViewOnMain()
        }
    }
}

private func createHostingViewOnMain() -> UIView {
    MainActor.assumeIsolated {
        let hosting = UIHostingController(rootView: MyView())
        return hosting.view
    }
}
模式 5:访问自定义 Actor
actor DataStore {
    var cache: [String: Data] = [:]

    nonisolated func synchronousRead(key: String) -> Data? {
        // Only safe if called from DataStore's executor
        assumeIsolated { isolated in
            isolated.cache[key]
        }
    }
}

常见错误

错误 1:压制编译器错误
// ❌ DANGEROUS: Using assumeIsolated to silence warnings
func unknownContext() {
    MainActor.assumeIsolated {
        updateUI()  // Crashes if not actually on main actor!
    }
}

// ✅ When uncertain, use proper async
func unknownContext() async {
    await MainActor.run {
        updateUI()
    }
}
错误 2:认为 GCD 主队列等同于 MainActor

它们通常相同,但并非总是如此。请查阅文档或改用 async。

错误 3:在 Async 上下文中使用
// ❌ Unnecessary — you already have isolation
@MainActor
func updateState() async {
    MainActor.assumeIsolated {  // Pointless
        self.state = .ready
    }
}

// ✅ Direct access
@MainActor
func updateState() async {
    self.state = .ready
}

@preconcurrency 不再需要的情况

如果协议之后添加了 MainActor 隔离:

// Library update:
@MainActor
protocol CaffeineThresholdDelegate: AnyObject {
    func caffeineLevel(at level: Double)
}

// Your code — @preconcurrency now warns:
// "@preconcurrency attribute on conformance has no effect"
extension Recaffeinater: CaffeineThresholdDelegate {
    func caffeineLevel(at level: Double) {
        // Direct access, no wrapper needed
    }
}

崩溃行为

根据 Apple 文档:

“如果当前上下文没有运行在该 Actor 的串行执行器上……此方法将以致命错误崩溃。”

触发崩溃是有意为之:与其让竞态条件损坏用户数据,不如直接崩溃。

资源

WWDC:2024-10169

文档:/swift/mainactor/assumeisolated、/swift/actor/assumeisolated

技能:axiom-swift-concurrency

评论

支持 Markdown