【问题标题】:Combine return request response with different format结合不同格式的返回请求响应
【发布时间】:2021-11-27 06:05:20
【问题描述】:

嘿,我有一个带有 viewModel 的 SwiftUI。当用户点击登录按钮时,我运行viewModel.registerAccount 函数。

func registerAccount() {
    authService.registerAccount(params: params)
        .sink { (dataResponse) in
            if let error = dataResponse.error {
                //
            } else {
                //
            }
        }.store(in: &cancellableSet)
}

在这个函数中,我调用了我的AuthService,我想在其中保存一些值并更改响应。

class AuthService {
    private let apiClient: APIClient = APIClient()
    private var guid: String?

    func registerAccount(params: [String: Any]) -> AnyPublisher<DataResponse<RegisterAccountResponse, Error>, Never> {
        let registerRequest = RegisterAccountRequest(params: params) // (url + method + params + ...)
        let apiRequest = apiClient.request(request: registerRequest)
        // i would like to read response, save guid
        // change response type and return only Error?
        return apiRequest
    }
}

还有APIClient 定义。

class APIClient {
    private let session: Session = Session(configuration: URLSessionConfiguration.default)
    func request<T: APIRequest>(request: T) -> AnyPublisher<DataResponse<T.Response, Error>, Never> {
        request
            .dataRequest(session: session)
            .publishDecodable(type: T.Response.self)
            .map { response in
                response.mapError { error in
                    return error
                }
            }
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
    }
}

但这并不能解决我的需求。我想知道是否有办法读取AuthService 中的响应,并返回Error? 类型的响应。

在某一时刻,我想到了这一点,也列在 AuthService 中,但我想更改响应并仅发送格式为 Error? 的对象。

func registerAccount(params: [String: Any]) -> 
AnyPublisher<DataResponse<RegisterAccountResponse, Error>, Never> {
    let registerRequest = RegisterAccountRequest(params: params)
    let apiRequest = apiClient.request(request: registerRequest)
        
    apiRequest.sink { dataResponse in
        if let guid = dataResponse.value?.guidFlow {
            self.guid = guid
        }
    }.store(in: &cancellableSet)
        
    return apiRequest
}

我也想过这个,但我正在寻找一种更结合/SwiftUI 的方法。

func registerAccount(params: [String: Any], completion: @escaping (Error?) -> Void) {
    let registerRequest = RegisterAccountRequest(params: params)
    let apiRequest = apiClient.request(request: registerRequest)
    
    apiRequest.sink { dataResponse in
        if let value = dataResponse.value {
            // save guid and return nill or backend error (format Error)
        } else {
            completion(dataResponse.error)
        }
    }.store(in: &cancellableSet)
}

【问题讨论】:

  • 只需要返回`AnyPublisher`吗?

标签: ios swift alamofire combine


【解决方案1】:

我觉得奇怪的第一件事是您的APIClient.request 似乎返回了AnyPublisher&lt;DataResponse&lt;RegisterAccountResponse, Error&gt;, Never&gt;。我希望它返回一个AnyPublisher&lt;RegisterAccountResponse, Error&gt;——一个报告响应或错误的流。

如果您有能力更改APIClient,我会更改它。如果您无法控制该代码,我们可以使用tryMap 解决它。

您似乎真的希望AuthService 上的registerAccount 返回一个发布单个GUID 或错误的发布者。可能看起来像这样:

class AuthService {
    private let apiClient = APIClient()

    func registerAccount(params: [String: Any]) -> AnyPublisher<UUID?, Error> {
        let registerRequest = RegisterAccountRequest(params: params)

        return apiClient.request(request: registerRequest)
            .tryMap { (response: DataResponse<RegisterAccountResponse, Error>) throws -> UUID? in
                switch response {
                    case .success(let registerAccountResponse) :
                        return registerAccountResponse.value?.guidFlow
                    case .failure(let error) :
                        throw error
                }
            }.eraseToAnyPublisher()
    }
}

【讨论】:

  • func request&lt;T: APIRequest&gt;(request: T) -&gt; AnyPublisher&lt;T.Response, Error&gt; { session.request(request.url, method: request.httpMethod, ...) .publishDecodable(type: T.Response.self) .map { response in response.mapError { error in return error } } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() }
  • 我尝试更改方法 APIClient 方法但我得到Cannot convert return expression of type 'AnyPublisher&lt;T.Response, DataResponsePublisher&lt;T.Response&gt;.Failure&gt;' (aka 'AnyPublisher&lt;T.Response, Never&gt;') to return type 'AnyPublisher&lt;T.Response, Error&gt;'。也许你可以帮我把它从那个 DataRequest 类型转换为你提到的响应类型。
  • 我不知道publishDecodable 正在返回什么类型。谷歌暗示它可能与 Alamofire 有关?如果是这样,并且文档与您的代码一致,那么我会将map 操作从您的APIClient 中取出。让它返回一个 DataResponse&lt;T.Response, Error&gt;... 虽然从类型签名来看,你的 RegisterAccountResponse Failure 子类型是 Never 这意味着响应永远不会失败。恐怕我们越深入了解您的特定类型以及您所依赖的库,我得到的帮助就越少。
猜你喜欢
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-04
  • 2019-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多