必须在主线程上进行调用,我可以获取数据,但是当我希望它显示错误消息时,它会崩溃

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

提问人:LordGrim 提问时间:1/25/2023 更新时间:1/25/2023 访问量:2167

问:

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

Api服务

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()
    }

我收到的错误“必须在主线程上进行调用”

我获取数据没有任何问题,但我想给出错误的应用程序崩溃了。

dispatchQueue 部分是否存在错误?

为什么我在这里收到错误?

我想做的是在互联网被切断或 api 没有响应时毫无问题地将错误消息带到屏幕上。

Swift 错误处理 UIAlerController 调度队列 networkonmainthread

评论


答:

1赞 jacksoor 1/25/2023 #1

看看你的,有两个调用不会发生在主线程上,特别是在失败的情况下。尝试将它们也包裹起来,看看它是否有效。ApiServicecompletionDispatchQueue.main

在我看来,确保视图控制器代码在主线程上运行不应该是的责任。更可靠的方法是将完成代码包装在:ApiServiceDispatchQueue.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)")
            }
        }
    }
}

评论

0赞 LordGrim 1/25/2023
谢谢杰克,你的回答奏效了,我明白了。感谢您的漂亮而简单的解释。