UITableViewCell as Header or Footer View - cocoa-touch

I know about UITableView reusable header and footer view
but in my case, i have UITableView Cells, which i need to place also in section headers and also in normal rows
if i use
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
MyCell * cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
// ...
return cell;
}
How does it work out with the reusing? (is the message to be available for reuse even than passed), or does this disable the cell reuse

The cells get dealloc'ed when they go off-screen. So they don't get reused. An easy way to verify this is to subclass UITableViewCell with the following
- (void)dealloc
{
NSLog(#"I got dealloc'ed");
}
and observe the console output as you scroll.

These has always worked fine. You first should create a prototype with that name, or register a custom nib with your custom section identifier. HOWEVER , I noticed this breaks in iOS 7 when you add new sections to the table dynamically. Reverting to a plain non-reusing UIView works. Really a shame!

Related

Reusing custom UITableViewCells, see old UIView pictures briefly before new pictures load

I have a custom UITableViewCell that contains a UIView, in which I display a couple of pictures.
In my tableView:cellForRowAtIndexPath: function, I call dequeueReusableCellWithIdentifier: to reuse old custom cells, and then I update them with new pictures.
The problem is that when I scroll quickly on my screen, I see flickers of the old pictures before the new ones are loaded, which is unattractive.
I've tried to fix this by:
implementing prepareForReuse in the custom TableViewCell implementation file; this led to the same three UIViews appearing over and over again, and in this case the new pictures stopped loading altogether
clearing the UIView right after calling dequeueReusableCellWithIdentifier by using a for loop to remove all subviews; the app now takes a really long time to load pictures.
What is the best way to fix this, and why do the above errors in my attempted fixes occur? Here is my current code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"Blah";
blahCell *someCell = (blahCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!someCell) {
//initialize cell
} else {
someCell.imageContainerView = nil;
}
... (other code here)
}
I'd try setting the cell's imageView property to nil as the first step in your table view data source method cellForRowAtIndexPath.
You can use this UIImageView Category by AFNetworking.
Whenever you have to set a new image you just need to call
[someCell.imageContainerView setImageWithURL:url placeholderImage:placeholderImage];
Now, whenever you scroll, if the image is not loaded you will see a placeholder image instead of seeing previous cell images.

Xcode Table View erased after assigning custom class to controller

I am using XCode 5, and I am having an issue with assigning class to a TableViewController
I made a form using tableViews within a TableViewController. The TableView has static cells that are the ones containing the textBoxes for user input.
The problem is that after designing the tableView, I added a custom class to it. When I run the program, the view is an empty table view, but in the storyboard looks like I design it.
So maybe after assigning the custom class (which is a new empty class UITableViewController) everything is either not being load or being re-instanced?
Added:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
return cell;
}
This is the default method.
You need to create custom class for UITableViewCell, instead of creating it for UITableView, as table view contains tableViewCell, as the default ones, but your cell contains textFields which is not by default. Let me know if you need more clarity here
None of the above helped me. This is what solved the problem:
What was going on? the problem was that even with Static Cells instead of Prototypes, the TableViews was trying to use his datasource to get the cells to display (The class that i assigned to its controller). It was easy then, i just had to erase the methods in the TableViewController Class.
Maybe because the class had an function that weren't suppose to be there, or because the TableView had the DataSource linked to it.
The result was a TableViewController with a static table.

How to dynamically create multiple UITableViews in one UIViewController

I'm new at developing with XCode and Objective-C and I hope you can help me.
The problem is, I have an UITableViewController with an UITableView (created with the InterfaceBuilder).
The cells under the section headers are expandable.
Now I want to dynamically create multiple UITableViews under the existing TableView.
The style will be the same like the existing TableView's style.
Could you tell me how it is possible to create these TableViews programmatically?
Thank you very much
Michael
From what you are saying try using a grouped table view. Check out this link for a quick overview, and go to the grouped table view section.
Edit found this example here:
Seems like it is what you are looking for. And a very cool idea also.
You'll have to just make your own custom header row and just put that as the first row of each section. Subclassing the UITableView or the headers that are on there now would probably be a huge pain and I'm not sure you can easily get actions out of them the way they work now. You could easily set up a cell to LOOK like a header, and setup the tableView:didSelectRowAtIndexPath to expand or collapse the section it is within manually.
If I were you I'd store an array of booleans corresponding the the "expended" value of each of your sections. You could then have the tableView:didSelectRowAtIndexPath on each of your custom header rows toggle this value and then reload that specific section.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
///it's the first row of any section so it would be your custom section header
///put in your code to toggle your boolean value here
mybooleans[indexPath.section] = !mybooleans[indexPath.section];
///reload this section
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
You'd then setup your number numberOfRowsInSection to check the mybooleans value and return either 1 if the section isn't expanded, or 1+ the number of items in the section if it is expanded.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (mybooleans[section]) {
///we want the number of people plus the header cell
return [self numberOfPeopleInGroup:section] + 1;
} else {
///we just want the header cell
return 1;
}
}
You would also have to update your cellForRowAtIndexPath to return a custom header cell for the first row in any section.

Why can't I define IBOutlets when using custom "prototype tableviewcells"

I have my own table view cell which is defined in my storyboard. I have also defined a custom UITableViewCell class for this special cell. So when I want to create an Outlet for my custom prototype cell I get an error that the Outlet cant be created.
Since this is not possible I have to do some ugly workarounds and use the tags in IB to reference the individual labels and buttons later on in my code.
I don't really see why this is not possible and I wonder if working with tags and [myCell viewWithTag:] is the best possible way to go here?
Because the outlet is a one-to-one connection between your controller and a specific item within the view. In the case of a prototype cell, it is simply a description of a cell that can have an arbitrary number of different items (i.e. rows in your table view). How would the controller know which item you are referring to (e.g. row 5 or 500)? That is why you are receiving the error message.
Lucas provided one method to refer to your connection via tags which works perfectly well.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentInIB"];
UIImageView *img = (UIImageView*) [cell.contentView viewWithTag:1];
//img.image = ...
//Access you prototype cell here to alter its style, example:
[[cell layer] setCornerRadius:10];
[cell setClipsToBounds:YES];
return cell;}
I assume you are using dynamic prototypes - in the attribute inspector of the tableview in the storyboard there is an option to select "static cells" or "dynamic prototypes". You can do what you are trying to do if you select "static cells" as there is only one cell in your tableview at run time for each cell in the storyboard. Using this approach you will only be able to use the cells you create in storyboard i.e. you will not be able to select the number of cells in your code.

Search result of UISearchDisplayController has other cell layout and behaviour than searched table

I am using storyboarding. I have an UITableView with one prototype cell. This cell is of style "subtitle". I have added a segue from the cell to the detailed view. So when the user taps a cell it will open the corresponding editor... That all works great.
Now I added a UISearchDisplayController an a UISearchBar, implemented the delegates. That works very well.
But in the search result table the cells are of style "default" and are not tapable. What do I have to do to get a result table looking and behaving like the "unsearched" table?
I would like to contribute for answer #1 this is what I did and it worked for me
in the method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
instead of assigning the cell from the parameter tableView
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
assign it directly from the TableView on the view so you have to replace this
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
with this
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Found the problem...
The method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
pulled the cell from the tableView, which is in the result case not the tableView from the storyboard but the resultTableView from the SearchDisplayController.
I now get the cell to display in both cases from the table view in the storyboard and now it works.
I've been using ios 7.0 and Xcode 5.0. I found that search display controller is using the same tableview layout as the delegate view controller. All you have to do is judge if the current tableview is the delegate view controller's tableview, or the search display controller's tableview. But remember to add the sentence
tableView.rowHeight = self.tableView.rowHeight;
in the following code snippet:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (tableView == self.searchDisplayController.searchResultsTableView)
{
tableView.rowHeight = self.tableView.rowHeight;//very important!
return [self.searchResults count];
}
else
{
...
return ...;
}
}
if you forget to implement that sentence, then the row of the table view of search display is only as high as a default row, which makes you think it doesn't look like the "unsearched" table.
There is a possible answer to this here. It may not work entirely for you, but as I explained, the UISearchDisplayController creates the table view.
Check the documentation and you can get a better understanding of it, but it states:
You initialize a search display controller with a search bar and a
view controller responsible for managing the original content to be
searched. When the user starts a search, the search display controller
is responsible for superimposing the search interface over the
original view controller’s view and showing the search results. The
results are displayed in a table view that’s created by the search
display controller. In addition to the original view controller, there
are logically four other roles. These are typically all played by the
same object, often the original view controller itself.
In my case UISearchDisplayController was using right cell type (custom) but height of cell was wrong so I had to use
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
method to fix it.