【问题标题】:Chain network calls sequentially in Combine在 Combine 中按顺序链式网络调用
【发布时间】:2020-12-30 14:44:49
【问题描述】:

我的目标是使用 Combine 链接多个(此时为两个)网络调用,如果第一次调用失败则断开链接。

我有两种对象类型:CategoryEntity 和 SubcategoryEntity。每个CategoryEntity 都有一个名为subcategoriesIDS 的属性。 第一次调用我需要获取所有子类别,第二次我将获取所有类别,然后我将创建一个CategoryEntityViewModel 的数组。 CategoryEntityViewModel 包含一个基于CategoryEntity 的subcategoriesIDS 的SubcategoryEntityViewModel 数组。

为了更清楚:

  1. 获取子类别
  2. 获取类别
  3. 为每个提取的子类别创建一个SubcategoryEntityViewModel 并存储在某处
  4. CategoryEntityViewModel 是为每个提取的类别创建的。此对象将使用CategoryEntity 对象和SubcategoryEntityViewModel 数组进行初始化,发现过滤subcategoriesIDS 之间的匹配ID 并存储SubcategoryEntityViewModel 数组

我现在的代码是:

class CategoriesService: Service, ErrorManager {
    static let shared = CategoriesService()
    internal let decoder = JSONDecoder()
    
    @Published var error: ServerError = .none
    
    private init() {
        decoder.dateDecodingStrategyFormatters = [ DateFormatter.yearMonthDay ]
    }
    
    func getAllCategories() -> AnyPublisher<[CategoryEntity], ServerError> {
        let request = self.createRequest(withUrlString: "\(AppSettings.api_endpoint)/categories/all", forMethod: .get)
        return URLSession.shared.dataTaskPublisher(for: request)
            .receive(on: DispatchQueue.main)
            .tryMap { data, response -> Data in
                guard let httpResponse = response as? HTTPURLResponse, 200..<300 ~= httpResponse.statusCode else {
                    switch (response as! HTTPURLResponse).statusCode {
                    case (401):
                        throw ServerError.notAuthorized
                    default:
                        throw ServerError.unknown
                    }
                }
                return data
            }
            .map { $0 }
            .decode(type: NetworkResponse<[CategoryEntity]>.self, decoder: self.decoder)
            .map { $0.result}
            .mapError { error -> ServerError in self.manageError(error: error)}
            .receive(on: RunLoop.main)
            .eraseToAnyPublisher()
    }
    
    func getAllSubcategories() -> AnyPublisher<[SubcategoryEntity], ServerError> {
        let request = self.createRequest(withUrlString: "\(AppSettings.api_endpoint)/subcategories/all", forMethod: .get)
        return URLSession.shared.dataTaskPublisher(for: request)
            .receive(on: DispatchQueue.main)
            .tryMap { data, response -> Data in
                guard let httpResponse = response as? HTTPURLResponse, 200..<300 ~= httpResponse.statusCode else {
                    switch (response as! HTTPURLResponse).statusCode {
                    case (401):
                        throw ServerError.notAuthorized
                    default:
                        throw ServerError.unknown
                    }
                }
                return data
            }
            .map { $0 }
            .decode(type: NetworkResponse<[SubcategoryEntity]>.self, decoder: self.decoder)
            .map { $0.result }
            .mapError { error -> ServerError in self.manageError(error: error)}
            .receive(on: RunLoop.main)
            .eraseToAnyPublisher()
    }
}

这些方法是有效的(sink 在另一个类中被调用,不认为它有用所以这里没有复制)但是我找不到正确的方法来链接它们。

【问题讨论】:

标签: swift combine


【解决方案1】:

使用 Combine 链接异步操作的方法是 flatMap。在 map 函数中生成第二个发布者。确保将任何需要的信息作为值传递给 map 函数,以便第二个发布者可以使用它。有关基本示例,请参阅 How to replicate PromiseKit-style chained async flow using Combine + Swift。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-16
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多