Custom UITableView section header views are breaking - iphone

I have a custom UIView subclass that i'm trying to use as a header for one of my grouped tableview sections. I save an instance of that view in the tableViewController and use that to return the height for the header section as well as the view itself. the problem is that somehow that instance variable changes from a UIView to a CALayer in the middle of a reloadData call which causes a crash, since the instance has a special method to return it's expected height. this is the code that crashes:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (section == 0)
{
return [self.dataHeader frameHeight];
}
return 0.0f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (section == 0)
{
return self.dataHeader;
}
return nil;
}
I set a breakpoint at the first return in the if block of the heightForHeaderInSection method, and it hits it 4 times; the first three return the dataHeader successfully, while the fourth time shows it to be a CALayer and crashes with a doesNotRecognizeSelector exception (my tableview has 2 sections if that makes a difference). Is there any reason why this happens, and is there a way to stop it?

What does your initialization code for dataHeader look like? When you initialize dataHeader, are you properly retaining it?
My guess is that your dataHeader view is getting released before you intended.

The problem seems to be that you have 2 sections and somehow the app thinks there are 4. Here's how I would debug this problem:
1) What is numberOfSectionsInTableView returning (is it implemented)?
I assume that each header method should be called n times, where n is the number of sections in your table. I would also assume that the app asks the aforementioned delegate what n is.
2) What are the values of section each time these delegates are called?
There should only be one call per section, unless I'm missing something, and I would be amazed if the delegate gets called more than once with the same section value.

Related

Adjust UITableViewCell Height and Indentation?

Two UITableViewCell related questions:
In my custom UITableViewCell I loop through an array (of which I do not know how many objects it holds) and add a UILabel displaying some text for each object in that array.
This means I have to adjust the height of the cell so that these labels fit in. How can I do this?
When going into edit mode, I have the cells indent, however I do not want this. I have tried the following:
cell.shouldIndentWhileEditing = NO;
and
-(BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
Both sadly failed, I have I no idea why. How could I possible remedy this?
Any help is much appreciated with either of these issues, thanks.
You can specify the height for every row with the delegate method [UITableViewDelegate tableView:heightForRowAtIndexPath:].
Just change what the method returns and the reload your table.
This method actually has nothing to do with the indendation of cell content:
Asks the delegate whether the background of the specified row should be indented while the table view is in editing mode.
You can try to set indentationWidth but I never managed to make it work.
Fortunately, it's easy to change everything you want in [UITableView layoutSubviews] method.
Example:
- (void)layoutSubviews {
[super layoutSubviews];
self.contentView.frame = self.bounds;
}
You may also need to set
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
{
return UITableViewCellEditingStyleNone;
}
For the dynamic height part there are plenty of other answers and a quick google found a tutorial here

Is there a way to force a refresh of just a single header in UITableView?

I have a UITableView where I want to force a refresh of just a specific section header row, not the data rows. For example, refresh the header for section 3. I know how to reload an entire section (header plus data), but can just the section header be refreshed?
EDIT: When data changes in one section of the table I want to update information in the header of a DIFFERENT section. Therefore, I need to get a reference to the section header and then refresh it.
If the header is a custom UIView, then you can just call setNeedsDisplay on the UIView rather than on the UITableView.
Well, in my case, after some asynchronous task i need to update my custom section header view.
and I get it to update it's height using :
This Swift 3+ Code
//to reload your cell data
self.tableView.reloadData()
DispatchQueue.main.async {
// this is needed to update a specific tableview's headerview layout on main queue otherwise it's won't update perfectly cause reloaddata() is called
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
UITableView does *not have any such method to reload only the header view/title ...You have to reload the whole section or the table.
I beg to differ. I've run into this while deleting rows with custom section headers and (at least in iOS 6) you can simply call:
[self tableView:self.tableView viewForHeaderInSection:[indexPath section]];
And as long as you have proper code to return a view in that method, you can easily refresh the header for a specific section:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if ([self tableView:tableView numberOfRowsInSection:section] == 0) {
return nil; //hide the header if there are no rows...
} else {
// configure or refresh the header...
}
}

Accessing "default" methods of UITableView

I try to set up a tableView. I use standard cells for all sections' rows except in the last section (containing one row). Thus, I would also like to use the standard layout for all those sections except that special one.
A short example is the following, my "special" cell is in section 3 (there is only one row):
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 3)
return 5;
return **????**;
}
At ??? I would like to return the width calculated from UITableView (just as if I did not implement the method).
[super self:tableView
heightForHeaderInSection:(NSInteger)section];
does not work. I know I can access
[tableView setionHeaderHeight]
which is by default 10 and obviously does not take into account that I have section headings for the other sections, which will require additional space. I tried that, but it will then get the sections too close (see screenshot):
(Note: the section I am interested in is the one which does not look like a cell: the one with the dates (invisible background)).
So, the easiest thing would be to hand over the layout to the standard implementation which is perfect - except for section3.
What are my options?
Just in case: there is a new constant introduced in iOS 5, called UITableViewAutomaticDimension. As the documentation says, you should return it from your delegate method when you want UITableView to use a default value.
So, the code for your case would be:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 3) {
return 5;
} else {
return UITableViewAutomaticDimension;
}
}
You seem a bit confused about heightForHeaderInSection - it returns the height of a table section header (this is the "title" of a table section), not a row. iOS calls this method to ask for the height of just a single section header, irrespective of any other section headers there might be.
If you want to use the default, just return [tableView sectionHeaderHeight] for any section other than 3 - you don't need to "take into account that [you] have other section headers", as it's asking for the height of the header for section alone. It will ask again for the heights of others (and compute the relative positions with of rows and other sections automatically).
You do not have a super implementation tableView:heightForHeaderInSection: since you are not subclassing any abstract base implementation for UITableViewDelegate. The table view is instead decided if the default height should be used by inspecting your delegate implementation to see if the method is available.
It is a quite a huge concept to wrap your head around, especially if coming from Java or C#. Methods in Objective-C protocols can be optional, and their absence means use default.
Your method should probably be implemented as:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
if (section == 3) {
return 5;
} else {
return 36;
}
}
The default height for grouped and plain tableviews are different (22points for plain). The default values are not exposed by UITableView, not even as private methods. File bug at http://bugreport.apple.com to make this a public constant.
After overriding heightForHeaderInSection and doing a side-by-side comparison, the height for the header in the first row is larger than the rest. This isn't pixel perfect, but it's very close:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
if (section == 0 ) {
return 46.0;
} else if (section == myCustomRow) {
return 12345.0; // custom height
} else {
return 36.0;
}
}

UITableView fixed header

How to disable scrolling for UITableView header, to be always visible? (To have column titles.)
I am not sure if I am getting what you mean, are you using a UITableViewController?
If you want to have a header that is not scrollable maybe you can try to put a UIView at the top of your tableview and add sublayers to it as needed.
If a tableview with multiple fixed section headers is what you want, I would suggest using different tableviews and adding UIViews on top of each one for the header.
For handling delegate and datasource use NSObject's - (BOOL)isEqual:(id)anObject .
For example:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([tableView isEqual:markosFirstTableView])
{
return 1;
}
else
{
return 5;
}
}
Does this help?

iPhone + UITableView + row height

I am setting the row height of my UITableView using following code
[tableView setRowHeight: 100.00];
I am using the single line as separator in the UITableView.
Eventhough setting the height above, height of row does not get change.
You should implement
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
delegate method. and return 100.0 there.
You should avoid the heightForRowAtIndexPath if all your rows are of similar height and use the rowHeight property. According to the documentation:
There are performance implications to using tableView:heightForRowAtIndexPath: instead of rowHeight. Every time a table view is displayed, it calls tableView:heightForRowAtIndexPath: on the delegate for each of its rows, which can result in a significant performance problem with table views having a large number of rows (approximately 1000 or more).
In the UITableViewController subclass it could be done, for instance, in the viewDidAppear method (the UITableViewController has a reference to the tableView):
self.tableView.rowHeight = 79.f;
The row height is baked into the cells when they are first displayed.
Did you set UITableView#rowHeight before setting the data source?
If not, do so.
If for whatever reason you can't, your other option is to call UITableView#reloadData after setting the row height.
I did like this, here tableobj is nothing but UITableView object in my application.
- (void)viewDidLoad
{
[super viewDidLoad];
[tableObj setRowHeight:100.0f];
}
Or handle it in numberOfRowsInSection: like:
- (NSInteger)tableView:(UITableView *)tblView numberOfRowsInSection:(NSInteger)section {
[tableObj setRowHeight:100.0f];
return [soandso count]; // soandso is my object
}
Because set the rowHeight before setting the data source. It worked for me (for equal row heights).
The better and cleaner solution is to implement the delegate function (Maybe not the best one if your UITableView has many rows ...).
Also, think that UITableVieCell are UIView so you could change their height firstly...
Delegates are very powerful in iPhone dev, here the UITableViewDelage:
http://developer.apple.com/iphone/library/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html
You can also change the indentForRow, displayCellForRow, heightForRow,edit stuff .....
I dont think there is such a method in UITableView...
Instead you can use the property rowHeight...
Try,
tableView.rowHeight =100;