我的内存缓存实现遇到问题,其中 fetchValue 未捕获第二个回调。我当前的设置涉及使用 Apollo GraphQL 和合并的 Future 来获取数据,但第二个回调没有按预期触发。
func myRequest<T, Q: GraphQLQuery>(query: Q) -> Future<Response<T>, CYGErrorType>? where T: RootSelectionSet {
return Future<Response<T>, CYGErrorType> { promise in
guard let futureFetchValue = self.fetchValue(query: query, cachePolicy: self.model.cachePolicy) as Future<Response<T>, CYGErrorType>? else {
promise(.failure(.default))
return
}
futureFetchValue
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
break
case .failure(let error):
promise(.failure(error))
}
}, receiveValue: { result in
print("API>> API>> response")
promise(.success(result))
})
.store(in: &self.cancellable)
}
}
==============
private func fetchValue<T, Query: GraphQLQuery>(query: Query, cachePolicy: CachePolicy) -> Future<Response<T>, CYGErrorType>? where T: RootSelectionSet {
return Future<Response<T>, CYGErrorType> { promise in
print("API>> hit")
apolloClient.fetch(query: query, cachePolicy: cachePolicy) { result in
switch result {
case .success(let graphQLResult):
let validateResponse = graphQLResult.isValid(query: query)
switch validateResponse {
case .success:
guard let data = graphQLResult.data as? T else {
promise(.failure(CYGErrorType.default))
return
}
let response = Response(value: data, response: nil, error: nil)
promise(.success(response))
print("API>> response")
case .failureWithError(let error):
promise(.failure(error))
}
case .failure(let error):
let cygError = self.graphQLErrorParsing(error: error, queryName: Query.operationName)
promise(.failure(cygError))
}
}
}
}
输出:
print("API>> hit")
print("API>> response")
print("API>> API>> response")
print("API>> response")
预期产量
print("API>> hit")
print("API>> response")
print("API>> API>> response")
print("API>> response")
print("API>> API>> response")
来自 fetchValue 的第二个回调没有从 myRequest 中捕获。我希望在输出中看到两个 API 响应,但第二个响应丢失了。看起来
Combine
Future
只支持第一个回调而不支持第二个回调,但我不知道如何正确处理它。
为什么 fetchValue 没有捕获第二个回调? 如何确保两个回调都被正确捕获和处理? 任何有关如何解决此问题的帮助或建议将不胜感激!
您的代码与回答您问题的人可能不熟悉的库(Apollo 客户端)密切相关,并且测试环境需要他们没有的 GraphQL 服务器 - 因此直接回答您的问题将很困难。
在您给出的示例中,函数
myRequest
调用 fetchValue
。 fetchValue
返回一个Future
,而myRequest
似乎将那个Future
包装在另一个Future
中,除了回显“fetchValue”的结果之外,它实际上没有任何用途。
我不明白你为什么这么做。 看起来
myRequest
和 fetchValue
确实是等价的 - 您应该能够完全删除 myRequest
并简单地调用 fetchValue
。
您暗示
apolloClient.fetch
可能会针对给定查询多次调用其完成回调函数。是这样吗?
如果是这样,那么按照评论中的建议,您可能需要使用
PassthroughSubject
(将返回类型表示为 AnyPublisher
)。
A
Future
表示在未来某个时间返回单个结果的单个请求。它是一个发出 one 值然后终止的流。 所以这不是一个好的模型 if apolloClient.fetch
将返回多个结果。
A
PassthroughSubject
是可以携带多个值的通用流。当遇到错误或流显式完成时它将终止。 (从您的代码中不清楚如何判断 apolloClient.fetch
何时完成发送值并且流应该终止)
忽略该细节,您可能需要的是这样的:
private func fetchValue<T, Query: GraphQLQuery>(query: Query, cachePolicy: CachePolicy) -> AnyPublisher<Response<T>, CYGErrorType>? where T: RootSelectionSet {
let resultSubject = PassthroughSubject<Response<T>, CYGErrorType>()
print("API>> hit")
apolloClient.fetch(query: query, cachePolicy: cachePolicy) { result in
switch result {
case .success(let graphQLResult):
let validateResponse = graphQLResult.isValid(query: query)
switch validateResponse {
case .success:
guard let data = graphQLResult.data as? T else {
resultSubject.send(completion: .failure(CYGErrorType.default))
return
}
let response = Response(value: data, response: nil, error: nil)
resultSubject.send(response)
print("API>> response")
case .failure(let error):
resultSubject.send(completion: .failure(error))
}
case .failure(let error):
resultSubject.send(completion: .failure(error))
}
}
return resultSubject.eraseToAnyPublisher()
}
此处代码创建一个
PassthroughSubject
,每次调用完成处理程序时,它都会发出通过该主题传递给回调的值。 在函数的底部,我们将主题转换为 AnyPublisher
,因为它是 PassthroughSubject
的事实是该函数之外的人员不需要知道的实现细节