Delegate returns nill in Swift(模型和ViewController之间的数据流)

Delegate returns nill in Swift (Data flow between Model and ViewController)

我正在 swift 中创建一个基本应用程序,我从 api 获取数据并显示它。我的模型 class 处理获取数据部分,我使用委托与 ViewController.

进行数据通信

然而,当获取的数据被传递到控制器时,由于某种原因它是空的。 这是我 know/have 尝试过的东西。

  1. 正在提取 JSON。数据已正确获取。
  2. 我尝试使用 viewWillAppear 和 viewDidLoad
  3. 我已在视图控制器中将委托设置为自身

抽象代码如下。

//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,因此您可以进一步改进。

注意:这是在没有编译器的情况下写在这里的,所以可能有一些语法需要调整。