Post

Replies

Boosts

Views

Activity

I can't use value inside my UICollectionView from API ( Swift, MVVM, UIKit)
I'm trying to make simple app that shows a list with values from API. The thing is that I can't use that same way like previous projects. I got a error message: failure(Swift.DecodingError.typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))) ViewController import UIKit import Combine class PokedexViewController: UIViewController { var subscriptions = Set<AnyCancellable>() private var pokedexListVM = PokedexListViewModel() var collectionView: UICollectionView? override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground setupCollectionView() } private func setupCollectionView() { let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() layout.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 0, right: 5) layout.itemSize = CGSize(width: view.bounds.size.width, height: 60) collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout) collectionView?.register(PokedexCollectionViewCell.self, forCellWithReuseIdentifier: PokedexCollectionViewCell.identifier) collectionView?.delegate = self collectionView?.dataSource = self view.addSubview(collectionView ?? UICollectionView()) //self.view = view setupViewModel() } private func setupViewModel() { pokedexListVM.$pokemons .receive(on: RunLoop.main) .sink(receiveValue: { [weak self] _ in self?.collectionView!.reloadData() }).store(in: &subscriptions) let stateHandler: (PokedexListViewModelState) -> Void = { state in switch state { case .loading: print("loading") case .finishLoading: print("finish") case .error: print("error") } } pokedexListVM.$state .receive(on: RunLoop.main) .sink(receiveValue: stateHandler) .store(in: &subscriptions) } } extension PokedexViewController: UICollectionViewDelegate, UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return pokedexListVM.pokemons.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell( withReuseIdentifier: PokedexCollectionViewCell.identifier, for: indexPath ) as? PokedexCollectionViewCell else { return UICollectionViewCell() } cell.configure(with: "\(pokedexListVM.pokemons[indexPath.row].name)") return cell } } ViewModel import Foundation import Combine enum PokedexListViewModelState { case loading case finishLoading case error } class PokedexListViewModel: ObservableObject { @Published private(set) var pokemons: [Pokedex.Results] = [] @Published private(set) var state: PokedexListViewModelState = .loading private var subscriptions = Set<AnyCancellable>() private var url = "https://pokeapi.co/api/v2/pokemon?offset=0&limit=898" //private let url = "https://jsonplaceholder.typicode.com/posts/" init() { loadPokemons() } private func loadPokemons() { state = .loading let valueHandler: ([Pokedex.Results]) -> Void = { [weak self] items in self?.pokemons = items } let completionHandler: (Subscribers.Completion<Error>) -> Void = { [weak self] completion in switch completion { case .failure: self?.state = .error print(completion) case .finished: self?.state = .finishLoading } } URLSession.shared.dataTaskPublisher(for: URL(string: url)!) .map{ $0.data } .decode(type: [Pokedex.Results].self, decoder: JSONDecoder()) .sink(receiveCompletion: completionHandler, receiveValue: valueHandler) .store(in: &subscriptions) } } Model import Foundation struct Pokedex: Codable { struct Results: Codable { let name: String let url: String } var results: [Results] var count: Int var next: String var previous: String? } I use pokeAPIV2 from that link: https://pokeapi.co/api/v2/pokemon?offset=0&limit=898 { "count": 1154, "next": "https://pokeapi.co/api/v2/pokemon?offset=3&limit=3", "previous": null, "results": [ { "name": "bulbasaur", "url": "https://pokeapi.co/api/v2/pokemon/1/" }, { "name": "ivysaur", "url": "https://pokeapi.co/api/v2/pokemon/2/" }, { "name": "venusaur", "url": "https://pokeapi.co/api/v2/pokemon/3/" } ] } I want to use the "name" data from that API. One thing that I noticed is that API starts from "{" and previous ones starts from "[".
3
0
991
Oct ’22