I'm currently using Moya alpha 15 with Combine Framework for my SwiftUI project. With Moya, I have a provider that's responsible for creating requests.
What I want:
Is this possible? If not, is there a better way to do this?
What I'm trying to do:
I need to show a profile image using the profileURL from Instance in a tableView. The height of each cell will be dynamic and based on the aspect ratio of each image. Each cell could have 1 + children profile images arranged differently.
Some sample code of my service call and data models:
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()
}
My attempt:
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 = $0
return instance
}
.eraseToAnyPublisher()
}
.collect()
.eraseToAnyPublisher()
}
which returns AnyPublisher<[Instance], MoyaError>
, but I'm looking to return AnyPublisher<InstanceResponseList, MoyaError>
.
What you did is mostly correct. You just need another level of nesting to be able to get the original instanceResponseList
value:
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()