when runnig the app when i added the UITableView and the cell it appears a purple warning saying: “UITableView.reloadData() must be used from main thread only”
i tried DispatchQueue but nothing different happened
GitHub Code: https://github.com/CarlosCardonaM/Youtube
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var model = Model()
var videos = [Video]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
// Set it's self as the delegate of the model
model.delegate = self
model.getVideos()
}
}
// MARK: - Model Delegate Methods
extension ViewController: ModelDelegate {
func videosFetched(_ videos: [Video]) {
// Set the returned videos to our videos property
self.videos = videos
// Refresh the tableview
tableView.reloadData()
}
}
// MARK: - TableView Delegate and Datasource Methods
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return videos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "VideoCell", for: indexPath)
// Configure the cell
// Get the title for the video in question
let title = self.videos[indexPath.row].title
cell.textLabel?.text = title
// Return the cell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
MODEL STRUCT
protocol ModelDelegate {
func videosFetched(_ videos:[Video])
}
class Model {
var delegate:ModelDelegate?
func getVideos() {
// Create a url object
let url = URL(string: Constants.API_URL)
guard url != nil else {
return
}
// Get a url session object
let session = URLSession.shared
// Get a data task from the url session
let dataTask = session.dataTask(with: url!) { (data, response, error) in
// Check if there were any errors
if error != nil || data == nil {
return
}
do {
// Parsing the data into video objects
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let response = try decoder.decode(Response.self, from: data!)
if response.items != nil {
// Call the "videosFetched" methods of the delegate
self.delegate?.videosFetched(response.items!)
}
dump(response)
}
catch {
}
}
// Kick off the task
dataTask.resume()
}
}
VIDEO STRUCT
struct Video : Decodable {
var videoID = ""
var title = ""
var description = ""
var thumbnail = ""
var published = Date()
enum CodingKeys: String, CodingKey {
case snippet
case thumbnails
case high
case resourceId
case published = "publishedAt"
case title
case description
case thumbnail = "url"
case videoId
}
init (from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let snippetContainer = try container.nestedContainer(keyedBy: CodingKeys.self, forKey: .snippet)
// Parse the title
self.title = try snippetContainer.decode(String.self, forKey: .title)
// Parse the description
self.description = try snippetContainer.decode(String.self, forKey: .description)
// Parse the punlished date
self.published = try snippetContainer.decode(Date.self, forKey: .published)
// Parse thumbnails
let thumbnailContainer = try snippetContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .thumbnails)
let highContainer = try thumbnailContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .high)
self.thumbnail = try highContainer.decode(String.self, forKey: .thumbnail)
// Parse video ID
let resourceIdContainer = try snippetContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .resourceId)
self.videoID = try resourceIdContainer.decode(String.self, forKey: .videoId)
}
}
struct Response: Decodable {
var items: [Video]?
enum CodingKeys: String, CodingKey {
case items
}
init (from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.items = try container.decode([Video].self, forKey: .items)
}
}