iOS - Объединить - Изменить тип издателя на дочерний тип - PullRequest
0 голосов
/ 02 марта 2020

У меня есть два объекта Codable:

struct Parent: Codable {
    let name: String
    let children: [Child]
}

struct Child: Codable {
    let name: String
} 

, которые я создал, чтобы соответствовать этому json:

{
    name: "test"
    children: (
        {
          name: "test2"
        },
        {
          name: "test3"
        }
     )
}

Я извлекаю json и декодирую его в Родительский объект, использующий эти методы:

func parent(_ url: String) -> AnyPublisher<Parent, Error> { 
    return dataFromURL(url)
        .map(\.value)
        .eraseToAnyPublisher()
}

struct Result<T> {
    let value: T
    let response: URLResponse
}

func dataFromURL<T: Decodable>(_ url: String, _ decoder: JSONDecoder = JSONDecoder()) -> AnyPublisher<Result<T>, Error> {
    let request = URLRequest(url: URL(string:url)!)
    return URLSession.shared
        .dataTaskPublisher(for: request)
        .tryMap { result -> Result<T> in
            let value = try decoder.decode(T.self, from: result.data)
            return Result(value: value, response: result.response)
        }
        .receive(on: DispatchQueue.main)
        .eraseToAnyPublisher()
}

Работает, но я хотел бы получить метод для получения массива дочерних объектов вместо родительского объекта, например:

func children(_ url: String) -> AnyPublisher<[Child], Error>  

Но Я не знаю, что мне нужно изменить .. Любая помощь будет оценена, спасибо!

1 Ответ

1 голос
/ 02 марта 2020

Вам просто нужно вызвать функцию parent и вызвать map для ее Publisher, чтобы получить обратно свойство children.

func children(from url: String) -> AnyPublisher<[Child], Error> {
    return parent(url)
        .map(\.children)
        .eraseToAnyPublisher()
}

Не имеет отношения к вашему вопросу, но я бы предложить избавиться от вашего Result типа. Прежде всего, это противоречит встроенному типу Swift Result. Во-вторых, сохранение URLResponse в случае успешных сетевых запросов, которые вернули действительные данные, на самом деле не добавляет никакой ценности. URLResponse в основном содержит значение в случае сбоя или если запрос не возвращает значение, но код ответа об успешном выполнении (200, 206 и т. Д. c).

Обновление: если вы хотите чтобы избавиться от метода parent(_:), вам просто нужно связать вызов map(\.children) с содержимым вашего исходного метода parent(_:). Чтобы позволить компилятору определить тип возвращаемого значения c для метода dataFromURL(_:), вам просто нужно указать KeyPath как \Parent.children во втором вызове map.

func children(from url: String) -> AnyPublisher<[Child], Error> {
    return dataFromURL(url)
        .map(\.value)
        .map(\Parent.children)
        .eraseToAnyPublisher()
}
...