Delegate returns nill in Swift(模型和ViewController之间的数据流)
Delegate returns nill in Swift (Data flow between Model and ViewController)
我正在 swift 中创建一个基本应用程序,我从 api 获取数据并显示它。我的模型 class 处理获取数据部分,我使用委托与 ViewController.
进行数据通信
然而,当获取的数据被传递到控制器时,由于某种原因它是空的。
这是我 know/have 尝试过的东西。
- 正在提取 JSON。数据已正确获取。
- 我尝试使用 viewWillAppear 和 viewDidLoad
- 我已在视图控制器中将委托设置为自身
抽象代码如下。
//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
}
这应该足以让您继续前进。散布着许多值得一看的最佳实践 examples/tutorials,因此您可以进一步改进。
注意:这是在没有编译器的情况下写在这里的,所以可能有一些语法需要调整。
我正在 swift 中创建一个基本应用程序,我从 api 获取数据并显示它。我的模型 class 处理获取数据部分,我使用委托与 ViewController.
进行数据通信然而,当获取的数据被传递到控制器时,由于某种原因它是空的。 这是我 know/have 尝试过的东西。
- 正在提取 JSON。数据已正确获取。
- 我尝试使用 viewWillAppear 和 viewDidLoad
- 我已在视图控制器中将委托设置为自身
抽象代码如下。
//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
}
这应该足以让您继续前进。散布着许多值得一看的最佳实践 examples/tutorials,因此您可以进一步改进。
注意:这是在没有编译器的情况下写在这里的,所以可能有一些语法需要调整。