Задать вопрос
@shevzoom
 dev., student at MEPhI

Как отфильтровать данные JSON в API со смешанными типами?

Иногда в API попадаются элементы с другого раздела или со значениям nil. (например data в первой ветки пустая)
И это неудобно при выводе на экран в ячейки.
6103efc4f0f53238894821.jpeg

Я сделал 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))
    }
}
  • Вопрос задан
  • 46 просмотров
Подписаться 1 Простой 4 комментария
Решения вопроса 1
briahas
@briahas
ObjC, Swift, Python
(copy)
По основному вашему вопросу - имхо, вы все сделали правильно. Через filter - наглядно и просто(см. в коментариях). Можете закрывать этот вопрос.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы