如何使用 Combine Framework 进行多个请求

How to have multiple requests using Combine Framework

我目前正在为我的 SwiftUI 项目使用 Moya alpha 15 和 Combine Framework。使用 Moya,我有一个负责创建请求的提供程序。

我想要的:

  1. 使用 getInstance(page: Int) 获取我的初始 instanceResponseList object。
  2. 从那个 instanceResponseList object,检查每个实例是否 hasChildren == true
  3. 如果 hasChildren == true,使用实例的 id 调用 getInstanceChildren(id: String)
  4. 来自 getInstanceChildren(id: String) 的响应将被映射并分配给 children: [Instance] 属性(response.data.instances)

这可能吗?如果没有,有更好的方法吗?

我想做什么:

我需要在 tableView 中使用 Instance 的 profileURL 显示个人资料图像。每个单元格的高度将是动态的,并基于每个图像的纵横比。每个单元格可以有 1 + children 个不同排列的个人资料图像。

我的服务调用和数据模型的一些示例代码:

    public struct InstanceResponseList: Codable {
        public var success: Bool
        public var data: InstanceResponse
    }

    public struct InstanceResponse: Codable {
        public var instances: [Instance]
        public var hasMore: Bool //for pagination
    }

    public struct Instance: Codable {
        public var id: String
        public var profileURL: String?
        public var hasChildren: Bool


        public var children: [Instance] // I want to make a request and append the children for each of my instances.

        enum CodingKeys: String, CodingKey {
            case id = "instance_id"
            case profileURL = "profile_url"
            case hasChildren = "has_children"
        }
    }

    public func getInstance(page: Int) -> AnyPublisher<InstanceResponseList, MoyaError> {
        return instanceProvider
            .requestPublisher(.allInstances(page: page, show: 10)) // page & show are parameters used for pagination, not relevant here
            .map(InstanceResponseList.self)
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
    }

    public func getInstanceChildren(id: String) -> AnyPublisher<InstanceResponseList, MoyaError> {
        return haptagramProvider
            .requestPublisher(.children(id: id))
            .map(InstanceResponseList.self)
            .receive(on: DispatchQueue.main)
            .eraseToAnyPublisher()
    }

我的尝试:

    public func getInstanceWithChildren(page: Int) -> AnyPublisher<[Instance], MoyaError> {
        
        return getInstance(page: Int)
            .flatMap { instanceResponseList -> AnyPublisher<Instance, MoyaError> in
                Publishers.Sequence(sequence: instanceResponseList.data.instances).eraseToAnyPublisher()
            }
            .flatMap { instance -> AnyPublisher<Instance, MoyaError> in
                return getInstanceChildren(id: instance.id).map {
                    let instance = instance
                    instance.children = [=11=]
                    return instance
                }
                .eraseToAnyPublisher()
                
            }
            .collect()
            .eraseToAnyPublisher()
    }

which returns AnyPublisher<[Instance], MoyaError>, 但我正在寻找 return AnyPublisher<InstanceResponseList, MoyaError>.

你所做的大部分是正确的。您只需要另一层嵌套即可获得原始 instanceResponseList 值:

getInstance(page: page)
   .flatMap { instanceResponseList in
       Publishers.Sequence(sequence: instanceResponseList.data.instances)
          .flatMap { instance in

              instance.hasChildren

                 ? getInstanceChildren(id: instance.id)
                      .map { children -> Instance in
                         var instance = instance
                         instance.children = children
                         return instance
                      }
                      .eraseToAnyPublisher()

                 : Just(instance)
                      .setFailureType(to: MoyaError.self)
                      .eraseToAnyPublisher()

          }
          .collect()
          .map { instances -> InstanceResponseList in
              var instanceResponseList = instanceResponseList
              instanceResponseList.data.instances = instances
              return instanceResponseList
          }
   }
   .eraseToAnyPublisher()