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

如何使用Publishers串行链式调用服务请求及相关问题

问题解答

1. 错误原因分析

你的startSession函数声明返回AnyPublisher<SocketManager?, Never>,但上游的getSession返回的是AnyPublisher<Session, Error>——它的Failure类型是Error,而你没有处理这个错误就直接拼接流,导致整个流的Failure类型仍为Error,和你声明的Never不匹配。

另外,Just(socket)本身是不会抛出错误的Never类型Publisher,你后面加的.catch完全多余,因为Just根本不会触发错误回调。

修正后的代码示例:

func startSession(uniqueId: String) -> AnyPublisher<SocketManager?, Never> {
    getSession(token: uniqueId)
        .map { response in
            self.setupSockets(sessionID: response.id)
        }
        .catch { _ in
            Just(nil)
        }
        .eraseToAnyPublisher()
}

这里用map直接把Session转换成SocketManager?,再用catch捕获上游getSession可能抛出的错误,返回Just(nil),这样整个流的Failure类型就转为Never,符合函数的返回类型声明。

2. 将Failure类型设为Never是否可行?

完全可行。你已经通过catch处理了所有可能的错误,确保流不会因错误终止;加上套接字仅创建一次,后续也没有错误触发的场景,用Never作为Failure类型可以明确告诉调用者:这个Publisher永远不会失败,只会输出一个值后完成。

3. ViewModel中的调用方式是否正确?

这种方式不算标准的串行链式调用——你是在getCredentialsPublisher的sink回调里手动订阅startSession,属于嵌套订阅,不是Combine推荐的流式写法,还会增加维护多个AnyCancellable的成本。

正确的做法是用Combine操作符(比如flatMap)把两个Publisher串成一个单一的流,优化后的代码:

var sessionSetupSubscriber: AnyCancellable?

sessionSetupSubscriber = getCredentialsPublisher(userInfo: object)
    .flatMap { credentials in
        self.startSession(uniqueId: credentials.id)
    }
    .sink(receiveCompletion: { completion in
        if case .failure(let error) = completion {
            print("凭证或会话获取失败:\(error)")
        }
    }, receiveValue: { socket in
        self.socketManager = socket
        // 直接在这里处理B逻辑:凭证获取完成后的其他操作
        self.handlePostCredentialsLogic()
    })

// 单独封装B逻辑
func handlePostCredentialsLogic() {
    // do something else that needs to be done when credentials are received.
}

关于订阅者的问题:不需要为A和B分别使用不同的订阅者。如果B逻辑不需要依赖套接字创建结果,只是需要在凭证获取成功后执行,也可以用handleEvents提前触发:

sessionSetupSubscriber = getCredentialsPublisher(userInfo: object)
    .handleEvents(receiveOutput: { credentials in
        // 在这里执行B逻辑
        self.handlePostCredentialsLogic()
    })
    .flatMap { credentials in
        self.startSession(uniqueId: credentials.id)
    }
    .sink(receiveCompletion: { completion in
        // 处理错误
    }, receiveValue: { socket in
        self.socketManager = socket
    })

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 04:01:12