如何解决如何在 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 举报,一经查实,本站将立刻删除。