Иногда в API попадаются элементы с другого раздела или со значениям nil. (например data в первой ветки пустая)
И это неудобно при выводе на экран в ячейки.
Я сделал init структуры как опционал, и туда стали приходить значения nil.
struct ResultItem: Codable {
let data: DataData?
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = (try? values.decode(DataData.self, forKey: .data))
}
}
Далее пытался использовать compactMap, чтоб убрать пустые значения из json и не создавать для них ячейку в tableVIew. Но попытка была неудачной.
Далее решил сделать инициализаторы в структурах, но тоже не помогло, первый элемент все равно приходит пустой и идет в tableView.
final class APICaller {
static let shared = APICaller()
var isPagination = false
struct Constants {
static let topHeadlinesURL = URL(string: "https://api.tjournal.ru/v2.0/timeline")
}
private init() {}
// пробовал и Result<ResultItem, Error>
public func getTopStories(completion: @escaping (Result<[ResultItem], Error>) -> Void) {
guard let url = Constants.topHeadlinesURL else {
return
}
let task = URLSession.shared.dataTask(with: url) {data, _, error in
if let error = error {
completion(.failure(error))
}
else if let data = data {
do {
let json = try JSONDecoder().decode(APIResponce.self, from: data)
completion(.success(json.result.items))
print("news: \(json.result.items.count)")
dump(json.result)
}
catch {
completion(.failure(error))
}
}
}
task.resume()
}
}
struct APIResponce: Codable {
let result: IsResult
}
struct IsResult: Codable {
let items: [ResultItem]
let lastID, lastSortingValue: Int
enum CodingKeys: String, CodingKey {
case items
case lastID = "lastId"
case lastSortingValue
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
items = (try values.decode([ResultItem].self, forKey: .items))
lastID = (try values.decode(Int.self, forKey: .lastID))
lastSortingValue = (try values.decode(Int.self, forKey: .lastSortingValue))
// items = items.compactMap{$0.data}
}
}
struct ResultItem: Codable {
let data: DataData?
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = (try? values.decode(DataData.self, forKey: .data))
}
}
struct DataData: Codable {
let author: SubsiteClass?
let title: String
let blocks: [Block]?
let subsite: SubsiteClass?
enum CodingKeys: String, CodingKey {
case author
case subsite, title, blocks
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
author = (try? values.decode(SubsiteClass.self, forKey: .author))
title = (try values.decode(String.self, forKey: .title))
blocks = (try? values.decode([Block].self, forKey: .blocks))
subsite = (try? values.decode(SubsiteClass.self, forKey: .subsite))
}
}
// MARK: - SubsiteClass / Раздел. (ex. "Новости")
struct SubsiteClass: Codable {
let name: String
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = (try values.decode(String.self, forKey: .name))
}
}
struct Block: Codable {
let data: BlockData
// let cover: Bool
}
struct BlockData: Codable {
let text : String
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
text = (try values.decode(String.self, forKey: .text))
}
}