Understanding the delegates in UITableView and UITableViewController - iphone

I am learning how to use the UITableView and UITableViewController in the iOS and I think I may have confused myself. I have created a simple TableView and I have 2 sections. Nothing complicated.
I have the following defined and it builds fine:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
// Section is going to be either 0 or 1, high or low
if (section == 0) {
return 1;
}
else {
return 2;
}
}
However what I don't understand is the definitions of the methods. Both methods have to return an integer so I understand the starting (NSInteger). The numberOfRowsInSection starts with tableView:(UITableView *)tableView and I don't understand why?
I'm am new to programming the iOS so be gentle :-) All help greatly appreciated.
Mike

The method name is "tableView:numberOfRowsInSection:". The first argument is the instance if UITableView which is asking the data source for the number of rows in a particular section. This is a useful convention as you might have a single object act as the data source for many table views or want to update the table view in some way when a delegate method is called. By passing the calling object to the delegate you avoid needing to have the delegate maintain an additional reference to that object.
Take a look at the NSURLConnection delegate methods dealing with authentication for an example of where this is really necessary.

tableView:(UITableView *)tableView is helpful if you need to know which tableView sent that delegate method.

This is Apple's naming convention for delegate and data source methods. numberOfSectionsInTableView: has no arguments other than the table view, so that argument is added at the end. tableView:numberOfRowsInSection: takes another argument, the index of the section in question. Apple has decided that, when there are other arguments, the calling object should go first, and the arguments come after that.

Check out the UITableViewController Class Reference
- (NSInteger)tableView:(UITableView *)tableView
The first part, NSInteger lets you know that you need to return a number return 1;, the second part (UITableView *)tableView lets you know that you are dealing with the UITableView class.

Related

What should cellForRowAtIndexPath return if the table is empty?

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
I think if the table is empty, namely that
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[BNUtilitiesQuick getBizs] count];
}
always return 0
I would expect that -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath should not be called at all
This is important. I am making a program to search through things and sometimes after some searching, there is no result being returned.
However, is called anyway and I got an exception. What should I do?
-tableview:cellForRowAtIndexPath: may be called before the table view has realised it has zero rows and so shouldn't be called.
Therefore your implementation needs to check that the value of the row being passed in is not outside the bounds of your array. If it is, you need to return an empty cell (the documentation states returning nil will raise an exception).
There is simply no way that tableView:cellForRowAtIndexPath: will be called when the tableView:numberOfRowsInSection: method returns 0. It is likely that the count is being returned incorrectly.
Often you would have a giant switch statement in a cellForRow... Meaning that you have to have a value to return in the default case. I usually return nil there.
This is required by the compiler to not show a warning, but it should never be actually called. This method is only called for row indexes that are possible due to what you reeturn in the numberOfSections and numberOdRowsInSection methods.
First print [[BNUtilitiesQuick getBizs] count];
in NSLog and see if it really returns 0.
If it shows 0, and if the cellForRowAtIndexPath: still gets called, I suspect there is some ghost hanging around there. :-)
What about returning 1 as count (or 10 for example), and that one cell will display dimmed text with "No Results" ?
(open your contacts app and search for something.. it will have about 10 rows , 9 are empty and 1 displays "no results")

Confused over UITableView numberOfRowsInSection syntax

I have a tab view that loads a table view for each of the tabs
First tab interface declares UITableView *tableView;
Second tab interface declares UITableView *favTableView;
When declaring the number of rows for the second table this works:
- (NSInteger)tableView:(UITableView *)favTableView numberOfRowsInSection:(NSInteger)section {
return [favList count];
}
But if I change it to:
- (NSInteger)favTableView:(UITableView *)favTableView numberOfRowsInSection:(NSInteger)section {
return [favList count];
}
the app crashes when I try to load the second tab
Is my mistake (a) not understanding which is a variable/reserved word, (b) giving each table a unique identifier ie favTableView, instead of reusing tableView.
Also the second table doesn't have a title bar
The delegate method you must implement is
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
In this method prototype, tableView: (note the colon) is a fixed name you cannot change. The second instance of tableView is simply a local variable name that has meaning within the method. The following would also be valid:
-(NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section
The delegate method names are what they are. You cannot decide that you want the delegate method names to be something else, or how would UITableView know what methods to call when it needed information from its delegate?
So, for your table favTableView, if you specified the object that implements the above delegate method as favTableView's delegate, then when called the local variable tv would in fact be the same as favTableView.
I can see where you'd be confused about this. The SDK uses 'tableView' for a lot of things: method prototype placeholder names, variable names, and who knows what else. It boils down to being able to read and understand Objective-C method signatures. :-) It's a little strange, until you get used to it.
The delegate probably uses pre-set method names, as you point out. There shouldn't be a functional problem with not reusing tableView, as you probably reuses favTableView anyway. The title bar-thing should be solved by manually setting the properties for the title in your custom tableView. If you are looking for headers, you have to set the properties for height and size.

NSMutableArray to table view

i am new to the iPhone development.
i need to display the NSMutableArray contents into UITableViewCell..
it is quite simple.. but, i want to know, how to add the NSMutableArray contents into table view at runtime?
please anyone help me..
thank you very much..!
Have you read the Table View Programming Guide?
In particular the section that talks about Creating and Configuring a Table View.
The little code snippets on those guides provide examples that deal with the simplest case, which is an array.
In short, you provide a "data source", which the table view asks for each row from. That data source is usually (but doesn't have to be) the ViewController that uses the table.
Make sure to check out the example applications linked to there if you need to see some working examples in Xcode itself.
You want to add total array to single cell or a tableView. If the answer is tableView, then you can directly give the values in the following method like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
cell.textLabel.text = [array objectAtIndex: indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [array count];
}
you can use like that.

(iphone) how to refer multiple tableview

Hi I have a view that contains 2 tableviews.
For a single view I know this delegate method can help me fill content of each row
(void) tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
But since I have 2 tableviews, how can I refer to each of them and fill content separately?
Thanks for helping!
The "current" tableview will pass a pointer to itself along as an argument when calling its delegate's methods like the one you mentioned.
So, all you need to do is to compare the pointer (tableView) to references of the two tableviews that you stored or added as property previously.
Proceed like so within your delegate methods:
if (tableView == myFirstTableView) {
//code to handle first tableview
} else if (tableView == mySecondTableView) {
//code to handle second tableview
}
Edit: Both tableviews need to share the same delegate for this to work, which would make sense anyway since they appear on the same view.
since you have two table view so you need implement proper if else condition where you need which table view is going to display.Ok
Make IBOutlet for both table.
then now in viewWillAppear
make datasource for the display(Array of data)
and
if(...)
{
firstTable.hidden=NO;
secondTable.hiden=YES;
[firstTable reloadData];
}
else
{
secondTable.hidden=NO;
firstTable.hidden=YES;
[[secondTable reloadData];
}
Now dont worry with every condition you would not require any condition in CellForRowAtIndexPath or didSelectRowAtIndexPath.
Further to Toastor's answer above, you may of course set different delegates and data sources for each table, although most often it is simpler to use the same delegate/data source for all NSTableViews in the same view.
I prefer to use property tag for distinguishing the desired UIView. The UITableView is a subclass of UIView, so it have this property too.

Delegates, can't get my head around them

Hey, I'm looking for useful resources about Delegates. I understand that the delegate sits in the background and receives messages when certain things happen - e.g. a table cell is selected, or data from a connection over the web is retrieved.
What I'd like to know in particular is how to use delegates with multiple objects. As far as I know, specifying the same delegate for an object (e.g. table cell) would cause the same events to be called for both the cells at the same time. Is there anything equivalent to instantiating a delegate for a particular object?
Thanks in advance!
In Cocoa, objects almost always identify themselves when calling a delegate method. For example, UITableView passes itself as the first parameter of the delegate message when calling it:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
If you wanted the same delegate to handle multiple UITableViews, then you just need a some conditional on the tableView object passed to the method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.myFirstTableView) {
// do stuff
} else if (tableView == self.mySecondtableView) {
// do other stuff
}
}
}
If you don't want to compare the object pointers directly, you can always use the tag property to uniquely identify your views.
Usually, if you have a delegate method that might have to receive messages from many different objects, you simply have the calling object pass itself to the delegate in the message (method call).
For example, if you wanted a delegate method to extract the text from a tableviewcell's label, the method definition would look something like:
-(void) extractTextFromLabelOfTableCell:(UITableViewCell *) theCallingCell{
...
NSString *extractedText=theCallingCell.textLabel.text;
}
You would call the method from a tableviewcell thusly:
[delegate extractTextFromLabelOfTableCell:self];
Each instance of the tableviewcell would send itself to the delegate and the delegate would extract that instance's text. In this way, a single delegate object could handle an arbitrarily large number of cells.
A delegate is a way of adding behaviors to a class without subclassing or for attaching a controller to a class.
In the table view example you gave, the delegate is extending or controlling the table, not the cell. The table is designed to have a controller, the cell is not. This design choice is why you can't specify cell-specific delegates.
However, delegate methods will always announce the source object (the one to which the delegate is attached) and relevant parameters (like the cell involved) so you should always be able to handle the action fully.
In your case, if you have a cell and you would like the cell to manage itself, then the delegate method (which will probably be implemented on your UITableViewController) can simply fetch the cell from the source table using its NSIndexPath (passed as a parameter to the delegate method) and invoke a method on the cell subclass to do its work.
I always liked Chris Sells' ".NET Delegates: A Bedtime Story"