Home > Net >  Call must be made on main thread i can get the data but when i want it to show error message it cras
Call must be made on main thread i can get the data but when i want it to show error message it cras

Time:01-25

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)")
            }
        }
    }
}
  • Related