You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何筛选Actor对象?迭代遇无限循环及隔离错误

解决方案

问题1:filter陷入无限循环的原因

原AsyncSequence实现中,next()方法每次调用都会重新创建data.makeIterator(),导致每次都返回集合的第一个元素,filter会持续处理同一个元素,进而引发无限循环。

问题2:Actor隔离属性访问错误的原因

makeAsyncIterator()是**非隔离(nonisolated)**方法,无法直接访问Actor的隔离属性data——Actor的属性仅允许在其自身隔离上下文中访问。

正确实现方案

我们需要让迭代器基于data的快照(副本)进行遍历,同时确保快照的获取操作在Actor隔离上下文中完成:

actor DataModel {
    typealias Details = (passed: Bool, scores: [Int])
    private(set) var data: [Int: Details] = [:]

    func update(_ value: (Bool, [Int]), forKey key: Int) {
        data.updateValue(value, forKey: key)
    }

    subscript(id: Int) -> Details? {
        get { data[id] }
        set { data[id] = newValue }
    }

    func removeAll() {
        data.removeAll()
    }
    
    // 异步返回data的快照,确保在Actor隔离上下文访问data
    private func snapshot() async -> [Int: Details] {
        data
    }
}

extension DataModel: AsyncSequence {
    typealias Element = (key: Int, value: Details)
    
    nonisolated func makeAsyncIterator() -> AsyncIterator {
        AsyncIterator(actor: self)
    }
    
    struct AsyncIterator: AsyncIteratorProtocol {
        private let actor: DataModel
        private var underlyingIterator: Dictionary<Int, Details>.Iterator?
        
        mutating func next() async throws -> Element? {
            // 首次调用时获取data快照并创建迭代器
            if underlyingIterator == nil {
                let snapshot = await actor.snapshot()
                underlyingIterator = snapshot.makeIterator()
            }
            // 复用同一个迭代器,避免无限循环
            return underlyingIterator?.next()
        }
    }
}

测试验证

调用filter和遍历的代码可以正常工作,不会再出现无限循环:

let data = DataModel()
await data.update((false, [1, 2]), forKey: 0)
await data.update((true, [3, 4, 5]), forKey: 1)
await data.update((false, [6,7,8,9]), forKey: 2)

let filtered = data.filter { el in
    el.value.passed || el.value.scores.count > 3
}

for try await i in filtered {
    print(i)
}
// 输出结果:
// (key: 1, value: (passed: true, scores: [3, 4, 5]))
// (key: 2, value: (passed: false, scores: [6, 7, 8, 9]))

方案说明

  1. 快照机制:每个迭代器在首次调用next()时,会异步获取当前data的快照,后续遍历都基于这个快照,避免迭代过程中data被修改导致的不一致。
  2. Actor隔离合规:通过Actor内部的异步方法snapshot()访问data,确保所有对隔离属性的操作都在Actor上下文内完成。
  3. 避免无限循环:迭代器复用同一个底层字典迭代器,遍历完成后会返回nil,终止循环。

内容的提问来源于stack exchange,提问作者Kevvv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 01:50:17