iOS 使用Combine 处理多个异步回调

问题描述 投票:0回答:1

我的内存缓存实现遇到问题,其中 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 没有捕获第二个回调? 如何确保两个回调都被正确捕获和处理? 任何有关如何解决此问题的帮助或建议将不胜感激!

ios swift graphql combine
1个回答
0
投票

您的代码与回答您问题的人可能不熟悉的库(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
的事实是该函数之外的人员不需要知道的实现细节

© www.soinside.com 2019 - 2024. All rights reserved.