首页 > 解决方案 > 结合不同格式的返回请求响应

问题描述

嘿,我有一个带有 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但我想更改响应并只发送一个对象 format 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)
}

标签: iosswiftalamofirecombine

解决方案


我发现奇怪的第一件事是您APIClient.request似乎正在返回一个AnyPublisher<DataResponse<RegisterAccountResponse, Error>, Never>. 我希望它返回一个AnyPublisher<RegisterAccountResponse, Error>-- 一个报告响应或错误的流。

如果你有能力改变APIClient我会改变的。如果您无法控制该代码,我们可以使用tryMap.

看起来您确实希望返回一个发布单个 GUID 或错误的发布者registerAccountAuthService这可能看起来像这样:

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()
    }
}

推荐阅读