首页 > 解决方案 > UITableView 如何与 UITableViewDataSource 一起工作?

问题描述

我是 Swift 的新手,我正在尝试了解tableView.dataSource = self与扩展中的功能的关系:

class ChatViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var messageTextfield: UITextField!

    var messages: [Message] = [
        Message(sender: "email", body: "Hey!" ),
        Message(sender: "email", body: "Hello!" ),
        Message(sender: "email", body: "What's up!" ),
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
        title = K.appName
        navigationItem.hidesBackButton = true
        tableView.dataSource = self
    }

    @IBAction func sendPressed(_ sender: UIButton) {
    }


    @IBAction func logOutPressed(_ sender: UIBarButtonItem) {
        do {
          try Auth.auth().signOut()
            navigationController?.popToRootViewController(animated: true)
        } catch let signOutError as NSError {
          print ("Error signing out: %@", signOutError)
        }
    }
}


extension ChatViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print(section)
        return messages.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: K.cellIdentifier, for: indexPath)
        cell.textLabel?.text = messages[indexPath.row].body
        return cell
    }
}

tableView.dataSource是故事板中的一个变量,它与名为 的扩展名中定义的两个函数不同tableView,后者恰好具有相同的名称。该变量tableView作为第一个参数传递给两个函数tableView,而不是在定义中使用。

tableView变量和函数之间的关系是什么,tableView以及如何在函数中使用变量,即使它不在函数的定义中?有什么作用tableView.dataSource = self

标签: iosswiftuitableview

解决方案


许多类UIKit使用这种“数据源”模式来填充自己的数据。除了UITableView, 还有UICollectionView,UIPickerViewUIPageViewControllerDataSource, 仅举几例。这个答案中所说的也可以应用于这些类。


与其让你一次性提供所有数据,不如UITableView只在需要时才请求数据。这是因为有时数据可能在 Internet 上,一次获取所有数据可能需要很长时间,不是吗?

好的,那么表格视图应该向谁询问数据?dataSource!_ 表视图如何知道它的数据源可以回答它的问题?通过确保数据源符合UITableViewDataSource协议,该协议定义了一堆方法。

因此,tableView.dataSource = self就是说:

tableView,如果你想问数据,就问self(的ChatViewController)!

通过实现UITableViewDataSource,我们说这个类能够为表格视图的问题提供答案

我们如何实际提供答案?通过实现数据源方法!

// this is asking:
// for section number "section" the table view "tableView", how many rows does it have?
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    print(section)
    return messages.count // we answer: it has as many rows as "messages.count"
}

// this is asking:
// for the row at the index path "indexPath", in the table view "tableView",
// what UITableViewCell should I display?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: K.cellIdentifier, for: indexPath)
    cell.textLabel?.text = messages[indexPath.row].body
    return cell // we answer: you should display this cell!
}

注意,虽然上面的两个数据源方法确实有名字,但是用andtableView来称呼它们更有用,这也是人们经常做的事情。numberOfRowsInSectioncellForRowAt

不太重要(对于这个问题),在这些方法中,tableView指的是参数,而不是你的类中声明的属性。要引用您的类中声明的属性,您需要self.tableView.

表格视图将在适当的时候调用这些方法,同时提供参数。例如,cellForRowAt当它需要显示一个新的单元格时会被调用。

我发现你对你的一些误解:

tableView.dataSource是情节提要中的一个变量

dataSource 属性在 中声明UITableView。您只能在故事板(或更准确地说,Xcode 的界面生成器)中看到它。dataSource并不是真正“来自”故事板。

该变量tableView作为第一个参数传递给两个函数tableView,而不是在定义中使用。

tableView是参数的名称。你没有通过任何东西。请记住,您正在声明这些方法,并且您不应该传递参数。调用者 - 表视图 - 是。

此外,您使用的是tableViewin 参数cellForRowAt,因为该参数隐藏了tableViewin 声明的属性ChatViewController


推荐阅读