我不能从 API 在 UICollectionView 中使用值( Swift、MVVM、UIKit)



我正在尝试制作一个简单的应用程序,显示一个包含API值的列表。问题是,我不能像以前的项目那样使用同样的方式。我收到一条错误消息:

failure(Swift.DecodingError.typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil)))

这是我的代码:

  1. 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
}

}
  1. 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)

}
}
  1. 型号
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?

}

我从该链接使用pokeAPIV2:https://pokeapi.co/api/v2/pokemon?offset=0&限制=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/"
}
]
}

我想使用";name";API的数据。我注意到的一件事是API从";{〃和前面的从"["开始。

您的模型应该是这样的:

import Foundation
struct Pokedex: Codable {
var results: [Results]
var count: Int
var next: String
var previous: String?
}
struct Results: Codable {
let name: String
let url: String
}

你的视图模型应该是这样的:

URLSession.shared.dataTaskPublisher(for: URL(string: url)!)
.map{ $0.data }
**.decode(type: Pokedex.self, decoder: JSONDecoder())**
.sink(receiveCompletion: completionHandler, receiveValue: valueHandler)
.store(in: &subscriptions)

相关内容

  • 没有找到相关文章

最新更新