我是否正确实现了 tableviewdatasource 以获取要显示的下载数据?

Am I implementing the tableviewdatasource correctly to get downloaded data to show?

我正在开发一个小应用程序来连接到我的网站,通过 PHP 网络服务下载数据,并在 table 视图中显示。开始之前,我遵循了 Jose Ortiz Costa (Article on Medium) 在 Medium 上的教程。

我调整了他的项目并获得了它 运行 验证 Web 服务是否正常工作并且能够获取数据。一旦我开始工作,我就开始了一个新项目,并尝试引入一些我需要进行网络连接的代码,并试图让它显示在同一场景的 table 视图中,而不是弹出窗口像何塞项目的场景。

这是我 运行 遇到一些问题的地方,因为我对 swift 编程语言还很陌生(开始了 Udemy 课程并一直在从中学习)它显示在 table 视图中。我可以看到请求仍在 sent/received,但我无法让它出现在 table 视图中(使用我的自定义 XIB 或以编程方式创建的单元格)。我以为我了解代码是如何分解的,甚至尝试通过 Viewcontroller.

的扩展将它从 UITableViewController 转换为 UITableviewDataSource

在这一点上,我很困惑,将继续检查代码并调整我认为可能是根本原因的内容。非常感谢任何有关如何修复的指示!

Main Storyboard Screenshot

用于解码我的数据的结构/Lead class:

import Foundation

struct Lead: Decodable {
    var id: Int
    var name: String
    var program: String
    var stage: String
    var lastAction: String
}

class LeadModel {

weak var delegate: Downloadable?
let networkModel = Network()

func downloadLeads(parameters: [String: Any], url: String) {
    
    let request = networkModel.request(parameters: parameters, url: url)
    
    networkModel.response(request: request) { (data) in
        let model = try! JSONDecoder().decode([Lead]?.self, from: data) as [Lead]?
        self.delegate?.didReceiveData(data: model! as [Lead])
    }
  }
}

ViewController:

import UIKit

class LeadViewController: UIViewController {

// Buttons
@IBOutlet weak var newButton: UIButton!
@IBOutlet weak var firstContactButton: UIButton!
@IBOutlet weak var secondContactButton: UIButton!

@IBOutlet weak var leadTable: UITableView!
let model = LeadModel()
var models: [Lead]?

override func viewDidLoad() {
    super.viewDidLoad()
    
    //Make Buttons rounded
    newButton.layer.cornerRadius = 10.0
    firstContactButton.layer.cornerRadius = 10.0
    secondContactButton.layer.cornerRadius = 10.0
    
    //Delegate
    model.delegate = self
}
    
    //Send request to web service based off Buttons Name
    @IBAction func findLeads(_ sender: UIButton) {
        let new = sender.titleLabel?.text
        let param = ["stage": new!]
        
        print ("findLead hit")
        model.downloadLeads(parameters: param, url: URLServices.leads)
    }

}

extension LeadViewController: UITableViewDataSource {

func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    print ("number of sections hit")
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
    guard let _ = self.models else {
        return 0
    }
    print ("tableView 1 hit")
    return self.models!.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    // Create an object from LeadCell
    let cell = tableView.dequeueReusableCell(withIdentifier: "leadID", for: indexPath) as! LeadCell
    
    // Lead selection
    cell.leadName.text = self.models![indexPath.row].name
    cell.actionName.text = self.models![indexPath.row].lastAction
    cell.stageName.text = self.models![indexPath.row].stage
    cell.progName.text = self.models![indexPath.row].program
    
    print ("tableView 2 hit")
    
    // Return the configured cell
    return cell
  }
}

extension LeadViewController: Downloadable {

func didReceiveData(data: Any) {
    
    //Assign the data and refresh the table's data
    DispatchQueue.main.async {
        self.models = data as? [Lead]
        self.leadTable.reloadData()
        
        print ("LeadViewController Downloadable Hit")
    }
  }
}

编辑

因此,经过一番搜索(好吧......大量搜索),我终于找到了一篇文章,其中说我必须将 class 设置为数据源。

leadTable.dataSource = self

所以这最终起作用了(在我添加了一个原型单元格之后,我的代码中使用了标识符)。我有一个自定义的 XIB,现在无法正常工作,这是我的下一个解决点。

您加载了数据,但未使用它。首先在viewDidLoad方法

的末尾添加如下语句
model.delegate = self

然后添加以下LeadViewController扩展名

extension LeadViewController: Downloadable {
    func dicReceiveData(data: [Lead]) {
        DispatchQueue.main.async {
            self.models = data
            self.tableView.reloadData()
        }
    }
}

还有一些建议: 使用按钮标题作为网络请求参数不是一个好的做法:

let new = sender.titleLabel?.text
let param = ["stage": new!]

最好把UI和逻辑分开。您可以使用按钮的 tag 属性(您可以在情节提要中或以编程方式配置它)来检查点击了哪个按钮。

您在 LeadModel class 中也有几个不必要的类型转换。你可以改变

let model = try! JSONDecoder().decode([Lead]?.self, from: data) as [Lead]?
self.delegate?.didReceiveData(data: model! as [Lead])

do {
    let model = try JSONDecoder().decode([Lead].self, from: data)
    self.delegate?.didReceiveData(data: model)
}
catch {}