Как я могу прочитать вложенные данные json с помощью Swift объединить - PullRequest
0 голосов
/ 10 марта 2020

Я только начал использовать объединение swift для обработки запроса и ответа на данные.

Возвращенные данные Json являются вложенными данными, которые мне понадобятся только в одной их части. например:

{
"page": 1,
"data": [
{
"id": 1,
"title": "news-1",
"content": "content 1"
},
{
"id": 2,
"title": "news-2",
"content": "content 2"
},
{
"id": 3,
"title": "news-3",
"content": "content 3"
}
],
"time": 202021313,
"description" :"xxxx"
}

Мне нужно будет использовать массив data.

Функции извлечения ниже:

    func fetchData() throws -> URLSession.DataTaskPublisher {
        let headers = [
            "Content-Type": "application/json",
            "cache-control": "no-cache",
        ]

        guard let url = URL(string: endpointStr ) else {
            throw APIError.invalidEndpoint
        }

        var request = URLRequest(url: url,
        cachePolicy: .useProtocolCachePolicy,
        timeoutInterval: 10.0)

        request.httpMethod = "GET"
        request.allHTTPHeaderFields = headers

        let session = URLSession.shared
        return session.dataTaskPublisher(for: request)
    }
        let publisher = try? fetchData()
        let decoder = JSONDecoder()
        let cancellable = publisher?
            .receive(on: DispatchQueue.main)
            .map {
                 $0.data
            }
            .decode(type: DataModel.self, decoder: decoder)
            .sink(receiveCompletion: { (completion) in
            switch completion {
            case .failure(let error):
                print("Error:")
                print(error)
            case .finished:
                print("DONE - get Publisher")
            }
        }, receiveValue: { data in
            print(data.title)
        })

Возвращенные данные: полные данные json, есть ли какой-нибудь элегантный способ получить только массив данных и преобразовать их в массив [DataModel] и обработать данные в receiveValue.

Я попытался отредактировать карту без удачи :

            .map {
                if let dataString = String(data: $0.data, encoding: .utf8) {
                    let dataDic = APIService.convertToDictionary(text: dataString)
                    if let DataArray = dataDic?["data"] {
                        return listDataDic! 
                    }
                 return $0.data
                }

1 Ответ

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

Пожалуйста, уточните, если я неправильно понял вопрос, но что, если вы используете другую модель для декодирования вашего [DataModel] и затем отобразите в декодированный массив [DataModel]?

Вот пример модульного теста. Response - это новая модель, которая декодирует массив [DataModel] во что-то, с чем вы можете работать.


import XCTest
import Combine

let data = """
{
  "page": 1,
  "data": [
    {
      "id": 1,
      "title": "news-1",
      "content": "content 1"
    },
    {
      "id": 2,
      "title": "news-2",
      "content": "content 2"
    },
    {
      "id": 3,
      "title": "news-3",
      "content": "content 3"
    }
  ],
  "time": 202021313,
  "description": "xxxx"
}
""".data(using: .utf8)!

class Response: Codable {
    var data: [DataModel]
}

class DataModel: Codable {
    let id: Int
    let title: String
    let content: String
}

class Test: XCTestCase {
    func testDecodeDataModel() {
        let e = expectation(description: "finished expectation")
        let decoder = JSONDecoder()
        let cancellable = Just(data)
            .decode(type: Response.self, decoder: decoder)
            .map { $0.data }
            .sink(receiveCompletion: { (completion) in
                // handle completion..
            }, receiveValue: { dataArray in
                print(dataArray.count) // here you can work with your [DataModel] array
                e.fulfill()
            })
        wait(for: [e], timeout: 1)
    }
}
...