如何用Combine实现等待WebSocket连接状态变更后执行请求?
解决方案
可以利用Combine的first(where:)操作符结合async/await的values属性实现该逻辑,让调用者无需提前检查连接状态,直接调用方法即可。
实现思路
- 直接处理当前状态:若已连接则执行请求,若未连接直接抛出异常
- 若处于连接中状态,监听
connectionStatus发布者,等待第一个非连接中的状态(connected或notConnected) - 根据最终状态决定继续执行请求或抛出异常
完整代码示例
假设ConnectionStatus枚举定义如下:
enum ConnectionStatus { case notConnected case connecting case connected } class WebSocketManager { @Published private(set) var connectionStatus: ConnectionStatus = .notConnected func sendRequest() async throws -> String { // 示例返回类型,可按需调整 // 处理当前已是最终状态的情况 switch connectionStatus { case .connected: return try await performRequest() case .notConnected: throw NSError(domain: "WebSocketError", code: -1, userInfo: [NSLocalizedDescriptionKey: "未连接到服务器"]) case .connecting: break // 进入等待逻辑 } // 等待连接状态变为connected或notConnected guard let finalStatus = await connectionStatus .publisher .first(where: { $0 != .connecting }) .values .first(await: .distantFuture) else { throw NSError(domain: "WebSocketError", code: -2, userInfo: [NSLocalizedDescriptionKey: "等待连接状态超时"]) } // 根据最终状态处理 switch finalStatus { case .connected: return try await performRequest() case .notConnected: throw NSError(domain: "WebSocketError", code: -1, userInfo: [NSLocalizedDescriptionKey: "未连接到服务器"]) case .connecting: // 理论上不会触发,已被first(where:)过滤 throw NSError(domain: "WebSocketError", code: -3, userInfo: [NSLocalizedDescriptionKey: "连接状态异常"]) } } // 实际执行WebSocket请求的私有方法 private func performRequest() async throws -> String { // 此处编写发送请求、处理响应的逻辑 return "请求成功响应" } }
关键细节说明
connectionStatus.publisher获取发布者,first(where:)过滤掉.connecting状态,只接收我们需要的最终状态.values将Combine发布者转换为async序列,first(await:)用于等待第一个符合条件的值(.distantFuture表示无超时,可按需设置具体超时时间)- 调用者只需直接调用
sendRequest(),方法内部自动处理状态等待、异常抛出逻辑
内容的提问来源于stack exchange,提问作者ambassador
相关产品推荐
相关产品推荐

