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

如何用Swift的async/await实现多播委托,让多客户端接收返回值?

用Swift Async/Await实现多播委托式的共享异步结果

要实现多个调用者共享同一异步任务的结果(即一次请求完成后所有等待的调用者都收到返回值),核心是复用同一个异步任务,避免重复发起请求,同时保证并发安全。以下是两种常用实现方式:

基础版:单次请求共享结果

适合不需要缓存结果,每次无等待时重新发起请求的场景:

actor DataSource {
    typealias Value = String // 替换为你的实际数据类型
    private var pendingTask: Task<Value, Error>?

    func fetchData() async throws -> Value {
        // 已有正在执行的任务,直接等待其结果
        if let task = pendingTask {
            return try await task.value
        }

        // 创建新任务并保存,供后续调用者复用
        let task = Task { () -> Value in
            defer {
                // 任务完成后清空,下次调用会重新发起请求
                pendingTask = nil
            }
            // 替换为你的实际异步请求逻辑
            try await Task.sleep(nanoseconds: 1_000_000_000)
            return "Fetched Data"
        }
        pendingTask = task

        return try await task.value
    }
}

关键逻辑说明

  • 用Actor保证pendingTask的线程安全访问,避免多个并发调用竞态创建重复任务
  • 第一个调用者创建异步任务,后续所有调用者直接等待该任务的结果
  • defer语句确保任务完成后清空pendingTask,下次无等待时会重新发起请求

缓存版:持久化共享结果

如果需要缓存结果,后续调用直接返回缓存值,无需重复请求:

actor DataSource {
    typealias Value = String
    private var cachedValue: Value?
    private var pendingTask: Task<Value, Error>?

    func fetchData() async throws -> Value {
        // 优先返回缓存值
        if let value = cachedValue {
            return value
        }

        // 已有执行中的任务,等待其结果
        if let task = pendingTask {
            return try await task.value
        }

        let task = Task { () -> Value in
            let value = try await fetchFromRemoteService()
            cachedValue = value // 缓存结果
            pendingTask = nil
            return value
        }
        pendingTask = task

        return try await task.value
    }

    // 封装实际的异步请求逻辑
    private func fetchFromRemoteService() async throws -> Value {
        try await Task.sleep(nanoseconds: 1_000_000_000)
        return "Cached Fetched Data"
    }
}

使用示例

多个并发调用fetchData(),都会共享同一请求的结果:

let dataSource = DataSource()

// 调用者1
Task {
    let value = try await dataSource.fetchData()
    print("Caller 1: \(value)")
}

// 调用者2
Task {
    let value = try await dataSource.fetchData()
    print("Caller 2: \(value)")
}

// 调用者3
Task {
    let value = try await dataSource.fetchData()
    print("Caller 3: \(value)")
}

错误处理说明

如果异步请求抛出错误,所有等待的调用者都会收到同一个错误,和回调模式下失败通知所有监听者的逻辑一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 21:46:18