StartScreenVC
import UIKit
class StartScreenVC: UIViewController {
private var apiService = ApiService()
override func viewDidLoad() {
super.viewDidLoad()
loadPopularMoviesData()
}
private func loadPopularMoviesData() {
apiService.getPopularMoviesData { [weak self] (result) in
switch result {
case .success(let listOf):
print(result)
case .failure(let error):
self?.showAlertWith(title: "Could not connect!", message: "Plese check your internet connection \n or try again later")
print("Error processing json data: \(error)")
}
}
}
// MARK: - Show Alert
func showAlertWith(title: String, message: String, style: UIAlertController.Style = .alert) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: style)
let action = UIAlertAction(title: "OK", style: .default) { (action) in
self.dismiss(animated: true, completion: nil)
}
alertController.addAction(action)
self.present(alertController, animated: true, completion: nil)
}
}
ApiService
import Foundation
class ApiService {
private var dataTask: URLSessionDataTask?
// MARK: - Get popular movies data
func getPopularMoviesData(completion: @escaping (Result<MovieData, Error>) -> Void) {
let popularMoviesURL = "https://api.themoviedb.org/3/movie/popular?api_key=4e0be2c22f7268edffde97481d49064a&language=en-US&page=1"
guard let url = URL(string: popularMoviesURL) else {return}
// Create URL Session - work on the background
dataTask = URLSession.shared.dataTask(with: url) { (data, response, error) in
// Handle Error
if let error = error {
completion(.failure(error))
print("DataTask error: \(error.localizedDescription)")
return
}
guard let response = response as? HTTPURLResponse else {
// Handle Empty Response
print("Empty Response")
return
}
print("Response status code: \(response.statusCode)")
guard let data = data else {
// Hndle Empty Data
print("Empty Data")
return
}
do {
// Parse the data
let decoder = JSONDecoder()
let jsonData = try decoder.decode(MovieData.self, from: data)
// Back to the main thread
DispatchQueue.main.async {
completion(.success(jsonData))
}
} catch let error {
completion(.failure(error))
}
}
dataTask?.resume()
}
The error I got 'Call must be made on main thread'
I'm getting the data without any problems, but the application I want to give an error crashes.
Is there a bug in the dispatchQueue parts?
Why am I getting an error here?
What I want to do is bring the error message to the screen without any problems, when the internet is cut off or the api is not responding.
CodePudding user response:
Looking at your ApiService
there are two calls to completion
which do not happen on the main thread, specifically in the failure cases. Try wrapping them in DispatchQueue.main
as well and see if it works.
In my opinion, it should not be the responsibility of the ApiService
to make sure your view controller code runs on the main thread. A more solid approach would be to wrap completion code in DispatchQueue.main
:
private func loadPopularMoviesData() {
apiService.getPopularMoviesData { [weak self] (result) in
DispatchQueue.main.async {
switch result {
case .success(let listOf):
print(result)
case .failure(let error):
self?.showAlertWith(title: "Could not connect!", message: "Plese check your internet connection \n or try again later")
print("Error processing json data: \(error)")
}
}
}
}