Разбор JSON с использованием Decodable в разделы TableView с массивом внутри массива - PullRequest
1 голос
/ 26 октября 2019

Я пытаюсь проанализировать данные из API в tableView с разделами. Конечным результатом будет заголовок раздела, который соответствует месяцу, и строки со списками видео, которые были опубликованы за месяц. Видео может не содержать постер или описание.

Я пытался реализовать функцию for in loop для обновления модели после извлечения данных, которая работала великолепно, пока я не попытался реализовать разделы. Я могу напечатать ответ json на консоль и получить полный ответ.

Вот пример оригинальной структуры JSON:

{
    "page": {
        "type": "videos",
        "sections": [{
            "title": "September",
            "videos": [{
                "title": "Some Video",
                "description": "Video Description",
                "poster": "",
                "url": "url"
            }]
        }, {
            "title": "August 2019",
            "videos": [{
                "title": "Some Video",
                "description": "",
                "poster": "Some Image",
                "url": "url"
            }, {
                "title": "Some Video",
                "description": "No Description",
                "poster"",
                "url": "url"
            }]
        }]
    }
}

Вот моя модель:

struct Root: Decodable {
    let page: Page  
}

struct Page: Decodable {
    let type: String
    let sections: [VideoSection]
}

struct VideoSection: Decodable {
    let title: String
    let videos: [Video]
}

struct Video: Decodable {
    let videoTitle: String
    let videoDescription: String?
    let poster: String?
    let url: String

    enum CodingKeys: String, CodingKey {
        case videoTitle = "title"
        case videoDescription = "description"
        case poster = "poster"
        case url = "url"
    }
}

Вот может Сетевой вызов с синтаксическим анализом:

func getVideoData(url: String){

    guard let videoUrl = URL(string: "Video_URL") else { return }
    URLSession.shared.dataTask(with: videoUrl) { (data, response, error) in
        guard let data = data else { return }
        do {
            let decoder = JSONDecoder()
            let responseData = try decoder.decode(Root.self, from: data)

            DispatchQueue.main.async {    
                self.videoTableView.reloadData()
            }

        } catch let err {
            print("Error", err)
        }
    }.resume()
}

Вот мой tableView:

var allvideosArray = [Video]()
var allSectionsArray = [VideoSection]()
var rootArray: Root?

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "customVideoCell", for: indexPath) as! CustomVideoCell

    cell.videoDescriptionPlaceholder.text = Video.CodingKeys.videoDescription.rawValue
    cell.videoTitlePlaceholder.text = Video.CodingKeys.videoTitle.rawValue
    return cell
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return allSectionsArray[section].title
}

func numberOfSections(in tableView: UITableView) -> Int {
    return allSectionsArray.count
}    

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return allvideosArray.count
}

Когда я пытаюсь print(responseData.page.sections.videos) я получаю ошибку "Значение типа«[VideoSection]» не имеет члена «videos», поэтому я полагаю, что проблема связана с массивом [videos] внутри массива [sections].

1 Ответ

1 голос
/ 26 октября 2019

Можно попробовать

var page:Page?

let responseData = try decoder.decode(Root.self, from: data)
self.page = responseData.page 
DispatchQueue.main.async { 
    self.videoTableView.reloadData()
} 

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: "customVideoCell", for: indexPath) as! CustomVideoCell
    let item = page!.sections[indexPath.section].videos[indexPath.row]
    cell.videoDescriptionPlaceholder.text = item.videoDescription 
    cell.videoTitlePlaceholder.text = item.videoTitle
    return cell
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return page?.sections[section].title
} 

func numberOfSections(in tableView: UITableView) -> Int {
    return page?.sections.count ?? 0
}


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return page?.sections[section].videos.count ?? 0

}
...