У меня большая часть функций работает и возвращает именно то, что я хочу. Тем не менее, у меня есть немного мозгов, когда дело доходит до того, чтобы взять массив photos
в response
и назначить их подходящим employees
, чтобы иметь возможность их отображать. Вот что происходит:
- Есть 4x кодируемых структуры:
Response
, Company
, Employee
и ProfileImages
. Response
- это основной объект, возвращаемый API, а затем декодированный в Company
, имеющий массив [Employee]
, каждый из которых имеет 3x ProfileImages
(маленький, средний и большой размер) - Там
companyPublisher
, который извлекает данные company
вместе с массивом employees
- Затем есть
photosPublisher
, который берет employees
массив из предыдущего шага и упорядочивает их, чтобы иметь возможность получить их profileImages.large
изображение профиля - Наконец, у меня есть
Publishers.Zip(companyPublisher, photosPublisher)
, который настраивает .sink()
издателя для ответа с завершением, как только все запрошенное будет получено.
Может кто-нибудь посоветует Какие шаги мне нужно предпринять, чтобы иметь возможность назначить правильный образ сотрудника фактическому сотруднику? Я думал о настройке необязательного UIImage
типа property
внутри кодируемой структуры Employee
, но все еще не уверен, как я могу go назначить соответствующий объект Future этому сотруднику.
Любое Помощь будет принята с благодарностью. Заранее спасибо!
Response.JSON
:
{
"success": true,
"company": {
"id": 64,
"name": "XYZ (Birmingham, AL)",
"enabled": true
},
"employees": [{
"id": 35,
"name": "Chad Hughes",
"email": "chad.hughes@company.com",
"profileImages": {
"small": "https://via.placeholder.com/150/09f/fff.png",
"medium": "https://via.placeholder.com/300/09f/fff.png",
"large": "https://via.placeholder.com/600/09f/fff.png"
}
}, {
"id": 36,
"name": "Melissa Martin",
"email": "melissa.martin@company.com",
"profileImages": {
"small": "https://via.placeholder.com/150/F2A/fff.png",
"medium": "https://via.placeholder.com/300/F2A/fff.png",
"large": "https://via.placeholder.com/600/F2A/fff.png"
}
}]
}
Models.swift
(кодируемые структуры):
struct Response: Codable {
let success: Bool
let company: Company
let employees: [Employee]
let message: String?
}
struct Company: Codable, Identifiable {
let id: Int
let name: String
let enabled: Bool
}
struct Employee: Codable, Identifiable {
let id: Int
let name: String
let email: String
let profileImages: ProfileImage
let profileImageToShow: SomeImage?
}
struct SomeImage: Codable {
let photo: Data
init(photo: UIImage) {
self.photo = photo.pngData()!
}
}
struct ProfileImage: Codable {
let small: String
let medium: String
let large: String
}
CompanyDetails.swift
:
class CompanyDetails: ObservableObject {
private let baseURL = "https://my.api.com/v1"
@Published var company: Company = Company()
@Published var employees: [Employee] = []
var subscriptions: Set<AnyCancellable> = []
func getCompanyDetails(company_id: Int) {
let url = URL(string: "\(baseURL)/company/\(company_id)")
// Company Publisher that retrieves the company details and its employees
let companyPublisher = URLSession.shared.dataTaskPublisher(for url: url)
.map(\.data)
.decode(type: Response.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
// Photo Publisher that retrieves the employee's profile image in large size
let photosPublisher = companyPublisher
.flatMap { response -> AnyPublisher<Employee, Error> in
Publishers.Sequence(sequence: response.employees)
.eraseToAnyPublisher()
}
.flatMap { employee -> AnyPublisher<UIImage, Error> in
URLSession.shared.dataTaskPublisher(for url: URL(string: employee.profileImages.large)!)
.compactMap { UIImage(data: $0.data) }
.mapError { $0 as Error }
.eraseToAnyPublisher()
}
.collect()
.eraseToAnyPublisher()
// Zip both Publishers so that all the retrieved data can be .sink()'d at once
Publishers.Zip(companyPublisher, photosPublisher)
.receive(on: DispatchQueue.main)
.sink(
receiveCompletion: { completion in
print(completion)
},
receiveValue: { company, photos in
print(company)
print(photos)
}
)
.store(in: &subscriptions)
}
}