微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在 Swift 中绘制视图之前从服务器加载数据

如何解决如何在 Swift 中绘制视图之前从服务器加载数据

我在快速加载数据和视图绘制时遇到问题。我的应用程序正在从服务器获取数据,但是在我获取数据之前,表视图正在加载,这就是为什么我需要重新加载它几次,这对我作为一个新开发人员来说看起来很奇怪,我认为这不应该这样工作。所以,我的问题是如何在加载视图之前从服务器加载数据。因为以我的方式很容易使应用程序崩溃,只需在加载数据之前点击即可。我用不同的方式尝试了 dispatchQeue,但不知道如何解决这个问题。

这是我如何从服务器获取数据并更新我的表视图的代码

import Foundation

typealias OnApiSuccesPeople = (people) -> Void
typealias OnApiError = (String) -> Void
typealias OnApiSuccesPlanet = (planet) -> Void

struct ApiService {
    static let shared = ApiService()
    
    let URL_BASE = "https://swapi.dev/api"
    let URL_PEOPLE = "/people"
    let URL_PEOPLE_PAGE_NUMBERFROMCYCLE = "/?page="
    let URL_PLANETS = "/planets"
    
    let session = URLSession(configuration: .default)
    
    func getResultsFromURL(onSuccess: @escaping OnApiSuccesPeople,onError: @escaping OnApiError,urlStringType: String) {

        let url = URL(string: "\(urlStringType)")!
        var request = URLRequest(url: url)
        request.httpMethod = "GET" // GET,PUT,POST,DELETE for some different api
        request.setValue("application/json",forHTTPHeaderField: "Content-Type")
        request.setValue("application/json",forHTTPHeaderField: "Accept")

        let task = session.dataTask(with: request) { (data,response,error) in
            
            dispatchQueue.main.async {

                if let error = error {
                    onError(error.localizedDescription)
                    return
                }

                guard let data = data,let response = response as? HTTPURLResponse else {
                    onError("Invalid data or response")
                    return
                }

                do{
                    if response.statusCode == 200 {
                        
                        let results = try JSONDecoder().decode(people.self,from: data)
                        onSuccess(results)
                    } else {
                        let err = try JSONDecoder().decode(APIError.self,from: data)
                        print("Code is \(response.statusCode)")
                        onError(err.detail)
                    }
                }
                catch {
                    onError(error.localizedDescription)
                }

            }
        }
        task.resume()

        }
import UIKit

class MainVC: UIViewController,UITableViewDelegate,UITableViewDataSource {


    
    @IBOutlet weak var charNaMetable: UITableView!
    
    
    

    override func viewDidLoad() {
        super.viewDidLoad()
    
        getResults()
        getPlanets()

        charNaMetable.delegate = self
        charNaMetable.dataSource = self
        
    }
    
    
    func getResults() {
        ApiService.shared.getResultsFromURL(onSuccess: { (people) in
            results.append(contentsOf: people.results)
            results.sort {$0.name < $1.name}
            self.charNaMetable.reloadData()
        },onError: { (error) in
            debugPrint(error)
        },urlStringType: "\(ApiService.shared.URL_BASE)\(ApiService.shared.URL_PEOPLE)")
        
        for i in 2...9 {
            ApiService.shared.getResultsFromURL(onSuccess: { (people) in
                results.append(contentsOf: people.results)
                results.sort {$0.name < $1.name}
                self.charNaMetable.reloadData()
            },onError: { (error) in
                debugPrint(error)
            },urlStringType: "\(ApiService.shared.URL_BASE)\(ApiService.shared.URL_PEOPLE)\(ApiService.shared.URL_PEOPLE_PAGE_NUMBERFROMCYCLE)\(i)")
        }

    }
    
    func getPlanets() {
            for i in 1...60 {
                ApiService.shared.getPlanetsFromURL(onSuccess: { (planet) in
                    resultsPlanets.append(planet)
                },onError: { (error) in
                    debugPrint(error)
                },urlStringType: "\(ApiService.shared.URL_BASE)\(ApiService.shared.URL_PLANETS)/\(i)")
            }
            
    }
    

    
    
    func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int) -> Int {
        return results.count
    }
    
    func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: "CharacterCell") as? CharacterCell {
            cell.updatecell(resuls: results[indexPath.row])
            return cell
        }
        
        return UITableViewCell()
    }
    
    func tableView(_ tableView: UITableView,heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 50
    }
    
    func tableView(_ tableView: UITableView,didSelectRowAt indexPath: IndexPath) {
        let detail = results[indexPath.row]
        performSegue(withIdentifier: "DetailedVC",sender: detail)
    }
    
    override func prepare(for segue: UIStoryboardSegue,sender: Any?) {
        initDetailedResults()
        
        
        if let detailedVC = segue.destination as? DetailedVC {
            detailedVC.initDetailedResultsForScreen(result: sender as! result)
            
        }
    }
    

}

解决方法

使用Combine框架进行发布和订阅

import Combine 

class ApiService: ObservableObject {

    @Published var items = Array<people>()

    // ...

    items = try JSONDecoder().decode(people.self,from: data)

    // ...

    

}

然后你可以监听控制器中的项目并更新 UITableView

import Combine

class MainVC: UIViewController {

    // ....
    private var cancellables = Set<AnyCancellable>()
    // ...
    override func viewDidLoad() {
        super.viewDidLoad()
    
        getResults()
        getPlanets()

        charNameTable.delegate = self
        charNameTable.dataSource = self

        ApiService.shared.$items
            .receive(on: DispatchQueue.main)
            .sink { [weak self] people in
                self?.results = people
                self?.charNameTable.reloadData()
                
            }
            .store(in: &cancellables)
    }
     
    

}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。