I understood before that
Delegate pattern is used only for invoking events to delegate instance and getting controls (like size / font / etc...).
Datasource pattern is only for getting data from datasource instance (like views / title / description / etc...)
But seems it was a nice illusion, after looking to Apple's UITableViewDelegate protocol I got confused because
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
Are delegate methods (but I was thinking that they are UITableViewDatasource methods)
Is this a dirty code from Apple, or I'm missing something important too understand difference between datasource and delegate?
EDIT:
Thanks #DBD for nice answer,
here is more confusion
Here is UITableViewDelegate method that returns View for drawing
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
And also there is a configuration in UITableViewDataSource
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
And oops, we can see a method that returns a View in UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
Here we have question why cellForRowAtIndexPath: and viewForHeaderInSection: are not in UITableViewDataSource
This is how I've always thought about it.
UITableViewDataSource to be primary data. What are the actual contents of the table. How many rows? What is the content of row X?
UITableViewDelegate was secondary and display data. How tall should it be, should it display in the selected state, and call backs for "hey I'm about to do something."
However I admit I see some of it as a fine line (and I don't buy some of the choices)
UITableViewDataSource has titleForHeaderInSection.
UITableViewDelegate has viewForHeaderInSection.
So if it's pure "data" title, it's the data source, but if includes a display wrapper with a view, it's the delegate. But wait, cellForRowAtIndexPath is a view and that's part of the data source, so why would you put viewForHeaderInSection in the delegate? While I can barely see the distinction between as "cell" as data and "title view" as delegate, I think the confusion of splitting "title" methods into different protocols is not preferable. I'm sure many might disagree with me, but it's just my opinion.
I think the critical distinction here arises from what you consider "data." From your question, I think you understand "data" to mean "any return value" – that is, methods which return void are delegate methods, and methods which return non-void are data source methods (since they pass something back to the sending table view).
This can sometimes be a useful approximation, but here is inaccurate. A table view's data is the contents that it displays – the stuff in the cells, the titles of sections, etc. Any other information, including that about layout (like row height) or display (like section headers) properly belongs in the delegate, since it is not about the contents of the table – merely about how to display those contents.
The two are very often related, which is why more often than not the same UITableViewController subclass implements both the delegate and data source, but imagine: you could have one object act as the data source and vend cells, then have a different object act as the delegate and provide heights for your rows based on completely different criteria. (Imagine a table where the user can resize rows, for example. You still provide the contents of each row, but the height – the delegate's responsibility – is drawing from a very different set of information.)
dataSource and delegate are both protocols but they are separated into two terms so that we can better understand what the methods are designed to do.
This means:
The dataSource protocol defines an API that supplies the data where delegate supplies the behavior.
dataSource is in the model layer and the delegate is in the control layer.
I think this is the correct outlook.
I have the same confusion with you, until I see the Apple's document.
The UITableViewDataSource protocol is adopted by an object that
mediates the application’s data model for a UITableView object. The
data source provides the table-view object with the information it
needs to construct and modify a table view.
As a representative of the data model, the data source supplies
minimal information about the table view’s appearance. The table-view
object’s delegate—an object adopting the UITableViewDelegate
protocol—provides that information.
UITableViewDataSource Protocol Reference
I don't understand your point.
The datasource protocol methods are all related to the data. The delegate protocol instead has methods regarding the appearance of the cells.
Related
I found a question in a quiz is "Which UIKit protocol contains the method –tableView:heightForRowAtIndexPath:?"
without taking any load the protocol comes in my mind was UITableViewDataSource. But when I checked apple developer documentation, I found I was wrong. UITableViewDelegate is the protocol who contain that method.
Before that I understood was that these height methods are part of Datasource protocol.
Is there any specific reason of placing them in UITableViewDelegate instead of UITableViewDataSource ?
Why following function are placed in UITableViewDelegate
heightForRowAt indexPath
heightForHeaderInSection
heightForFooterInSection
and Why following function are placed in UITableViewDataSource
numberOfSectionsInTableView
numberOfRowsInSection
Before now I thought these are similar type of function so these methods must be placed in same protocol.
Please make this clear to me.
Thanks in advance
UITableViewDelegate means you provide answers to requests about the layout of the table and about actions the user performs on the tableview.
UITableViewDatasource means you provide data for the sections and rows of a table and you act on messages that change a table's data.
For more in details, Check DataSource and Delegate
numberOfSectionsInTableView and numberOfRowsInSection are functions that answer questions about the data to be displayed which is why they are to be found in the DataSource protocol.
The heightFor... functions don’t answer anything about the underlying data but only on the way the data is displayed. This is why they are part of the Delegate protocol.
Does that make sense to you?
The datasource supplies the data, the delegate supplies the behavior.
In MVC, datasource is in the model layer and the delegate is in the control layer.
Actually, on second thought, the datasource is usually controller that is lower down, closer to the model. I don't think I've ever used a model object as my datasource.
The UI prospects of the UITableView are provided by the UITableViewDelgate methods and the data (we are not talking about the data to be used inside the cell, just the information about UI (section, row, etc.) repetitions) needed to construct the UI is provided by UITableViewDataSource methods.
Why is tableView:canMoveRowAtIndexPath: is UITableViewDataSource protocol and not in UITableViewDelegate protocol?
Similar methods (e.g. tableView:canFocusRowAtIndexPath:) are in Delegate protocol. I don't think it's a mistake, so can anyone explain why such method is part of the data source and not the delegate?
A general explanation of which methods belong to data source protocols and which belong to delegate protocols is also appreciated.
The delegate methods generally have to do with the appearance of the table view.
The data source methods generally have to do with the content of the table view. It's often the case that the displayed content's order is fixed. Say the table view was displaying stops on a bus line, or the chapter headings of a book. You can't let the user reorder those: it isn't something that the content itself supports.
Notice that both delegate and data source are actually involved in the decision as to whether a row can move. The data source gets the method you named, but the delegate gets asked tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: at the same time.
The UITableViewDatasource protocol documentation:
The UITableViewDataSource protocol is adopted by an object that
mediates the application’s data model for a UITableView object. The
data source provides the table-view object with the information it
needs to construct and modify a table view.
As a representative of the data model, the data source supplies
minimal information about the table view’s appearance. The table-view
object’s delegate—an object adopting the UITableViewDelegate
protocol—provides that information.
The required methods of the protocol provide the cells to be displayed
by the table-view as well as inform the UITableView object about the
number of sections and the number of rows in each section. The data
source may implement optional methods to configure various aspects of
the table view and to insert, delete, and reorder rows.
Hope, that clears things out.
EDIT: With my own words (but repeating the docs): Datasource declares methods those somehow directly or indirectly affect/reflect the data model, whereas the method tableView:canFocusRowAtIndexPath: can't be said similar to tableView:canMoveRowAtIndexPath: because it has nothing to do with the data. That said, datasource carries constructive character, delegate - informative.
I'm an iOS newbie and I would like to know how to detect when the user scrolls and reaches the bottom of an UITableView so I can load new data into the table.
I would also like to know where such a method should be implemented (the tableview's class or the view controller in which this tableview exists)
Cheers!
You can use -(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath to and check if the last cell will be shown in the TableView's data source.
iOS' TableViewController takes care of that automatically. It asks its datasource only for the currently visible rows of the table (tableview.cellForRowAtIndexPath)
See the documentation for the UITableViewDatasource Protocol Reference
If you've got a "known dataset" (as in, you don't need to make a network call to fetch new data), then like #zizoft said, it'll be handled automatically in tableview.cellForRowAtIndexPath
If, however, you've got an "unknown dataset", (as in, you'll need to pull down data from the internet), you'll need to do something a bit more interesting - #ansible's suggestion would be appropriate in that case.
So I know what a delegate is and I know how to implement it and everything, but this definition throws me off a little bit. "Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object." Can someone explain how this applies to something like this
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath ? What are the two objects and which object act on behalf of another object. I have an idea on what it is, but I need to make sure.
In your example, the table view controller (presumably that's the table view's delegate) acts on behalf of the table view. The class that implements the delegate method(s) acts on behalf of the class that defines the delegate interface.
As a user scrolls up and down in an uitableview cells get destroyed and created.
Is there a way to detect when a cell is going to be or has been destroyed?
Assuming that by "getting destroyed" you actually are referring to a cell getting reused, simply implement prepareForReuse within your UITableViewCell derived class.
prepareForReuse
Prepares a reusable cell for reuse by the table view's delegate.
- (void)prepareForReuse
Discussion
If a UITableViewCell object is reusable—that is, it has a reuse
identifier—this method is invoked just before the object is returned
from the UITableView method dequeueReusableCellWithIdentifier:. For
performance reasons, you should only reset attributes of the cell that
are not related to content, for example, alpha, editing, and selection
state. The table view's delegate in tableView:cellForRowAtIndexPath:
should always reset all content when reusing a cell. If the cell
object does not have an associated reuse identifier, this method is
not called. If you override this method, you must be sure to invoke
the superclass implementation.
Availability
Available in iOS 2.0 and later.
See Also
– initWithFrame:reuseIdentifier:
#property reuseIdentifier
Declared In
UITableViewCell.h
Without going into the implications of suitability or performance, another option might be to periodically check what cells remain visible, using the visibleCells method of the UITableView class:
- (NSArray *)visibleCells
As per the documentation:
Returns an array containing UITableViewCell objects, each representing a visible cell in the receiving table view.
You can subclass UITableViewCell and override it's dealloc method.
Any good reason to do it assuming you are reusing the cells to save the resources ?
What you're attempting to intercept is part of the internal implementation of UITableView and how it manages its cells. While there are ways in which you can attempt to intercept such behavior, I would suggest that you avoid using them, as there is no guarantee that future implementations of UITableView will maintain this behavior.
It would be better in cases such as this to consider a different approach: be it design and implement your own table class, or change your code logic.
As stated above, cells aren't destroyed when the leave the screen. However there are some things you can do, to track related actions, depending on what you are trying to do.
First there is a delegate message:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
This is called before a cell enters the screen. Another possibility is the already stated prepareForReuse method of a cell.
Another approach would be: Try and override willMoveToSuperview: or any other of the related methods. I am not sure if this is fired after the cell becomes invisible, but it might work.
Best regards,
Michael