Reputation: 4023
I'm new to Swift and I'm trying to understand how tableView.dataSource = self
relates to the functions within the extension:
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
is a variable from the storyboard, which is different from the two functions defined in the extension called tableView
, which just happens to have the same name. The variable tableView
is being passed as the first argument to both of the functions tableView
and not being used within the definition.
What is the relationship between the variable tableView
and the function tableView
and how the variable is being used in the function even though it's not in the definition of the function? And what does tableView.dataSource = self
do?
Upvotes: 0
Views: 151
Reputation: 272685
Many classes in UIKit
uses this "data source" pattern to populate themselves with data. Other than UITableView
, there's also UICollectionView
, UIPickerView
and UIPageViewControllerDataSource
, just to name a few. What is said in this answer can also be applied to those classes too.
Instead of making you give it all the data all at once, UITableView
asks for the data only when it needs. This is because sometimes the data could be, say, on the Internet, fetching them all at once could take a long time, couldn't it?
Okay, so who should the table view ask for the data? The dataSource
! How does the table view know that its data source can answer its questions? By ensuring that the data source conforms to the UITableViewDataSource
protocol, which defines a bunch of methods.
Therefore, tableView.dataSource = self
is saying:
Hey
tableView
, if you want to ask for the data, just askself
(theChatViewController
)!
By implementing UITableViewDataSource
, we are saying that this class is able to provide answers to table view's questions.
How do we actually provide the answers? By implementing the data source methods!
// 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!
}
Note that although the above two data source methods do indeed have the name tableView
, it is more useful to refer to them as numberOfRowsInSection
and cellForRowAt
, and this is also what people often do.
Less importantly (for this question), in these methods, tableView
refers to the parameter, not the property declared in your class. To refer to the property declared in your class, you need self.tableView
.
The table view will call these methods whenever appropriate, also supplying the parameters. For example, cellForRowAt
will be called when it needs to display a new cell.
A few misconceptions of yours that I spotted:
tableView.dataSource
is a variable from the storyboard
The dataSource
property is declared in UITableView
. You are merely able to see it in the storyboard (or more accurately, Xcode's Interface Builder). dataSource
is not really "from" the storyboard.
The variable
tableView
is being passed as the first argument to both of the functionstableView
and not being used within the definition.
This tableView
is the name of the parameter. You are not passing anything. Remember that you are declaring these methods, and you are not supposed to pass parameters. The caller - the table view - is.
Furthermore, you are using the tableView
parameter in cellForRowAt
, because the parameter hides the tableView
property declared in ChatViewController
.
Upvotes: 2