我正在快速创建一个基本应用程序,我从 api 获取数据并显示它。我的 Model 类处理获取数据部分,我使用委托与 ViewController 进行数据通信。
但是,当获取的数据传递到控制器时,由于某种原因,它是空的。 这是我知道/已经尝试过的事情。
抽象代码如下。
//Model Class
protocol DataDetailDelegate {
func datadetailFetched(_ datadetail: DataDetailItem)
}
class Model {
var datadetaildelegate: DataDetailDelegate?
func fetchData(ID: String) {
let url = URL(string: Constants.Data_URL + ID)
guard url != nil else {
print("Invalid URL!")
return
}
let session = URLSession.shared.dataTask(with: url!) { data, response, error in
if error != nil && data == nil {
print("There was a data retriving error!")
return
}
let decoder = JSONDecoder()
do {
let response = try decoder.decode(MealDetail.self, from: data!)
if response != nil {
DispatchQueue.main.async {
self.datadetaildelegate?.datadetailFetched(response)
}
}
} catch {
print(error.localizedDescription)
}
}
session.resume()
}
}
//View Controller
import UIKit
class DetailViewController: UIViewController, DataDetailDelegate {
@IBOutlet weak var instruction: UITextView!
var model = Model()
var datadetail : DataDetailItem?
override func viewDidLoad() {
super.viewDidLoad()
model.datadetaildelegate = self
model.fetchData(ID: data.id)
if self.datadetail == nil {
print("No data detail available")
return
}
self.instruction.text = datadetail.instruction
}
func datadetailFetched(_ datadetail: DataDetailItem) {
self.datadetail = datadetail
}
}
正如评论中提到的,上面的代码有很多问题,但主要的问题是没有认识到
fetchData
的异步性质。
下面是一个粗略的解决方案,它解决了代码中的关键问题,而不是解决所有问题的最佳实践。 例如,您还可以检查错误和响应代码的内容,并通过完成处理程序将它们传回(可能作为结果类型)。
对于初学者,请简化您的
fetchData
,以便它获取数据,然后通过完成处理程序以异步方式处理该数据。 另外,不要称其为模型,因为它实际上不是。
class SessionManager {
func fetchData(withID id: String, completion: @escaping (data) -> Void) {
guard let url = URL(string: Constants.Data_URL + ID) else {
print("Invalid URL!")
return
}
let session = URLSession.shared.dataTask(with: url) { data, response, error in
guard error == nil, let data = data else { //could be done far better by checking error and response codes
print("There was a data retriving error!")
return
}
completion(data)
}
session.resume()
}
然后调整视图控制器,以便它创建会话管理器并获取数据,但在完成处理程序中对其进行处理。 我只添加了相关内容。
class DetailViewController: UIViewController, DataDetailDelegate {
lazy var sessionManager = SessionManager()
var datadetail : DataDetailItem?
override func viewDidLoad() {
super.viewDidLoad()
sessionManager.fetchData(withID: data.id){ [weak self] data in
let decoder = JSONDecoder()
do {
let response = try decoder.decode(MealDetail.self, from: data)
DispatchQueue.main.async {
self?.datadetail = response
self?.instruction.text = datadetail.instruction
}
} catch {
print(error.localizedDescription)
}
}
}
// rest of view controller
}
这应该足以让你继续前进。 有许多最佳实践示例/教程值得一看,这样您就可以进一步完善内容。
注意:这是在没有编译器的情况下编写的,因此可能有一些语法需要调整。