Swift 中委托返回 null(模型和 ViewController 之间的数据流)

问题描述 投票:0回答:1

我正在快速创建一个基本应用程序,我从 api 获取数据并显示它。我的 Model 类处理获取数据部分,我使用委托与 ViewController 进行数据通信。

但是,当获取的数据传递到控制器时,由于某种原因,它是空的。 这是我知道/已经尝试过的事情。

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

抽象代码如下。

//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
    } 
}




ios swift model-view-controller uikit
1个回答
1
投票

正如评论中提到的,上面的代码有很多问题,但主要的问题是没有认识到

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
 }

这应该足以让你继续前进。 有许多最佳实践示例/教程值得一看,这样您就可以进一步完善内容。

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

© www.soinside.com 2019 - 2024. All rights reserved.