Как заполнить один объект модели несколькими связанными URL-запросами? Зависимость запроса? - PullRequest
0 голосов
/ 23 апреля 2020

У меня есть объект модели данных, который я должен заполнить несколькими сетевыми запросами.

Моя модель выглядит следующим образом

struct CO2Data: Identifiable, Codable {
    let id = UUID()
    let totalCO2: Double
    let dailyAverage: Int
    let calendar = Calendar.current
    let dateString: String
    let emissionStats: EmissionStats

let driveLog: String 
    // It is an ID to get the trip details

    let trip : Trip
    // This is what needs to be filled from the next URL request using driveLog


    enum CodingKeys: String, CodingKey {
        case id
        case totalCO2 = "totCO2"
        case dateString = "stDt"
        case dailyAverage = "avg"
        case emissionStats = "emisStats"
        case drLogRefId = "drLogRefId"
        //Not having case trip here breaks the conformance to codable
        // and results in error
    }
}
struct Trip: Codable {
    let startTime: String
    let endTime: String
    let startLat: String
    let startLong: String
    let endLat: String
    let endLong: String
}

Это поток сетевых запросов и ответов

  1. запрос на получение CO2Data и декодировать его с помощью JSONDecoder ()

  2. использовать свойство driveLog в извлеченных данных CO2D, чтобы сделать еще один сетевой запрос для получения объекта Trip.

  3. Результат второго сетевого запроса должен быть добавлен к объекту CO2Data в свойстве trip.

Как мне go узнать об этом. Можно ли даже сохранить данные Trip в CO2?

Я использую Combine & URLSession.shared.dataTaskPublisher (for: URLRequest) для этого, но я могу полностью использовать простую старую задачу с простыми данными. Существуют ли известные способы обработки зависимостей запросов, подобных этой? Я не использую сторонние библиотеки и wi sh, чтобы придерживаться URLSession.

JSON Объекты выглядят так

// for CO2Data
[
  {
    "stDt": "2019-11-17T16:00:00.000+0000",
    "totCO2": 50,
    "avg": 0,
    "emisStats": {
      "wea": 10,
      "aggDr": 10,
      "tfc": 10,
      "tirePress": 0,
      "ac": 10,
      "seatHeater": 10
    },
    "drLogRefId": "5dc20204199f752c7726a8f0"
  }
]

//for Trip
[
  {
    "id": "5dc20204199f752c7726a8f0",
    "startTime": "...",
    "startLat: "...",
    "startLong: "...",
    "endLat: "...",
    "endLong": "...",
  }
]

Ответы [ 2 ]

1 голос
/ 26 апреля 2020

Вот как вы можете достичь своей цели. Вам нужно сделать Trip необязательным во время первого сетевого вызова, поскольку у вас нет данных для установки там. Убедитесь, что обрабатываете это правильно во время json декодирования.

Затем используйте flatMap, чтобы сделать второй сетевой вызов. Используйте zip, чтобы дождаться завершения обоих запросов и передать данные результата в расширение CO2Data.init.

Полный код, где fetchCO2TripData вернет CO2Data с Trip:

struct CO2Data: Identifiable, Codable {
    let id = UUID()
    /// TODO: add other properties
    let driveLog: String
    let trip : Trip?
}

struct Trip: Codable {
    let startTime: String
    let endTime: String
    let startLat: String
    let startLong: String
    let endLat: String
    let endLong: String
}

func fetchCO2Data() -> AnyPublisher<CO2Data, Error> {
    /// TODO: Replace with actual network request
    Empty().eraseToAnyPublisher()
}

func fetchTripData(by driveLog: String) -> AnyPublisher<Trip, Error> {
    /// TODO: Replace with actual network request
    Empty().eraseToAnyPublisher()
}

func fetchCO2TripData() -> AnyPublisher<CO2Data, Error> {
    let co2Publisher = fetchCO2Data().share()
    let tripPublisher = co2Publisher.flatMap { fetchTripData(by: $0.driveLog) }

    return co2Publisher
        .zip(tripPublisher)
        .map { CO2Data(co2data: $0, trip: $1) }
        .eraseToAnyPublisher()
}

extension CO2Data {
    init(co2data: CO2Data, trip: Trip) {
        self.driveLog = co2data.driveLog
        self.trip = trip
    }
}

PS Я бы рекомендовал создать высокоуровневую модель, которая будет состоять из обоих сетевых вызовов, чтобы исключить необязательное отключение:

struct Model {
    let co2Data: CO2Data
    let trip: Trip
} 
0 голосов
/ 23 апреля 2020

В зависимости от сложности окружающих данных посмотрите либо на

  • Операции: Вы можете указать другие операции, от которых зависит эта операция.
  • DispatchGroup: С DispatchGroup.enter(), DispatchGroup.leave() и, наконец, DispatchGroup.notify() вы также можете смоделировать зависимости отправляемых задач, которые вы выполняете.

Удачи.

...