I recieves json data from api and totally confused what should I do next to pass this data to custom cell with imageView and labels in order to update UI in tableView.
Getting JSON
import Foundation
struct Breed: Codable {
let name: String?
let origin: String?
let life_span:String?
let temperament: String?
let description: String?
let wikipedia_url: String?
let image: Image?
}
struct Image: Codable {
let url: String?
}
func getDataFromCatsApi() {
let url = URL(string: "https://api.thecatapi.com/v1/breeds")
let task = URLSession.shared.dataTask(with: url!) { data, _ , error in
let decoder = JSONDecoder()
if let data = data {
let breed = try? decoder.decode([Breed].self, from: data)
print (breed as Any)
} else {
print (error as Any)
}
}
task.resume()
}
All data is printed correctly.
In ViewController I have a tableView with custom cell.
import UIKit
class MainVC: UIViewController {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
title = "Cats"
view.backgroundColor = .systemBackground
getDataFromCatsApi()
}
}
extension MainVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",
for: indexPath) as? CustomTableViewCell
return cell ?? CustomTableViewCell()
}
}
Class for custom cell. Here I have imageView and labels for displaying data from json.
import UIKit
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var catImageView: UIImageView!
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var originLabel: UILabel!
@IBOutlet weak var addToFavButton: UIButton!
}
CodePudding user response:
First of all, you are not returning anything from getDataFromCatsApi().
Since it is an asynchronous call, you have to implement a way to get the values either by using a callback or a delegate. In this case callback would suffice.
Then once you receive a value from the api call, set those values in func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
in which you can use cell.nameLabel.text = <received value>
and etc.
CodePudding user response:
First of all declare only those properties as optional which can be nil
struct Breed: Decodable {
let name, origin, lifeSpan, temperament, description: String
let wikipediaUrl: String?
let image: Image?
}
struct Image: Decodable {
let url: String?
}
In getDataFromCatsApi
add a completion handler
func getDataFromCatsApi(completion: @escaping (Result<[Breed],Error>) -> Void ) {
let url = URL(string: "https://api.thecatapi.com/v1/breeds")
let task = URLSession.shared.dataTask(with: url!) { data, _ , error in
if let error = error { completion(.failure(error)); return }
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
completion(Result { try decoder.decode([Breed].self, from: data!) })
}
task.resume()
}
In MainVC
declare a data source array
var cats = [Breed]()
Replace viewDidLoad
with
override func viewDidLoad() {
super.viewDidLoad()
title = "Cats"
view.backgroundColor = .systemBackground
getDataFromCatsApi {[unowned self] result in
DispatchQueue.main.async {
switch result {
case .success(let breed):
self.cats = breed
self.tableView.reloadData()
case .failure(let error): print(error)
}
}
}
}
and the table view datasources methods with
extension MainVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cats.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",
for: indexPath) as! CustomTableViewCell
let cat = cats[indexPath.row]
cell.nameLabel = cat.name
cell.originLabel = cat.origin
}
}
To load the pictures is beyond the scope of the question. There are libraries like SDWebImage or Kingfisher to load and cache images asynchronously.
CodePudding user response:
I have attached the code please check
extension MainVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Breed.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",
for: indexPath) as? CustomTableViewCell
cell.nameLabel.text = Breed[indexPath.row].name // see here
return cell ?? CustomTableViewCell()
}
}
CodePudding user response:
I am using a structure similar to this
import UIKit
class MainVC: UIViewController {
@IBOutlet weak var tableView: UITableView!
var Breed: [Breed]!
override func viewDidLoad() {
super.viewDidLoad()
title = "Cats"
view.backgroundColor = .systemBackground
getDataFromCatsApi()
}
}
extension MainVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Breed.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CustomTableViewCell
cell.yourLabelName.text = Breed[indexPath.row].name
return cell
}
}