Adding controls programmatically in UITableViewCell in static UITableView - ios

I have a static UITableView to which I am populating through NSDictionary in cellForRowAtIndexPath method.
NSString *key = [sectionKeys objectAtIndex:[indexPath section]];
NSArray *contents = [sectionContents objectForKey:key];
NSString *contentForThisRow = [contents objectAtIndex:[indexPath row]];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[[cell textLabel] setText:contentForThisRow];
Thinks working well, I also need to add controls to tableviewcells and every cell has different controls. When I programmatically add UITextField to cell1 the view after running is fine till 5 sections, but when I scroll my tableview further down, the cell of section 6 also gets a UITextField control. Same is happening with UIDatePicker, that first 5 sections of my tableview are fine but on scrolling the tableview the last two sections also get the UIDatePicker control.
Note: I have nine sections in table view each having one cell with the exception of first two sections that contain two cells.

What I understood:
The layout of your cells is getting messed up and controls from one cell go to the other one.
What I suggest:
It is a common problem, I faced it a while ago and it was extremely frustrating. After a few hours of googling I found a solution: Use different cell identifiers for cells with different controls.
Example:
5 cells: 2 cells with only a UITextField, 1 cell with UITextField and a UILabel and 2 cells with UIImageView. Use 3 different cell identifiers. 1 for the cells with only a UITextField, 1 for the cells with UIImageView and 1 for the cell with UITextField and a UILabel.
Hope it helps.

Related

dequeueReusableCellWithIdentifier: returns nil even after creating cell instance

I am trying to use a UITableView with a .xib file. I have done it in the past with storyboards, where you declare a reuse id in a dynamic prototype. I have this code inside the - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath function which should work:
NSString *ReuseId = #"DefaultCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ReuseId];
if (cell == nil) {
NSLog(#"cell == nil");
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ReuseId];
}
However, when I run this, instead of printing cell == nil once it prints it for every row.
Why??
Thanks.
How many rows do you have? It should create up to to 11 or 12 at first on iPhone. Depending on the height of the tableview and the heights of the cells.
So if you have less rows than cells fit on the view, cell reuse will never happen and is not needed.
if (cell == nil) {
NSLog(#"cell == nil");
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:ReuseId];
} else {
NSLog(#"We have a reused cell!");
}
try to repeat your rows several times and scroll slowly. Now every time you are just about to scroll the first pixel of a new cell on the view, it should print "We have a reused cell!".
The first time when you open table view there will be no cells to reuse because all of them will be actually in use. Cells start being reused when you start scrolling the table and some cells start disappearing from the top.
update
Let's say you have a table view that can partially display 6 rows (5.5 by height). When UITableViewController loads the table with the cells, it creates 6 cell instances because all of them must be displayed at the same time.
When you start scrolling and the first cell is hidden, it gets added to reusable cell set. That's when creating 8th cell (because 7th will be created newly, 'cause 1st one will still be visible by half height) the first one will be reused.

iOS: Customizing TableView cell to mimic music player

Is there an easy way of having a tableview cell like we see here with numbering like this and the border around. Is this created using different sections?
You need to create a custom UITableViewCell.
If you're using storyboards look here:
See this link http://mobile.tutsplus.com/tutorials/iphone/customizing-uitableview-cell/
If not here is a rundown:
Basically create a new class that inherits from UITableViewCell and a XIB. Drag a UITableViewCell to the XIB and set it to the class that you created previously.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CustomCellIdentifier = #"CustomCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (cell == nil) {
//*- Load your custom XIB. objectAtIndex:0 says load the first item in the XIB. Should be your UITableViewCell that you dragged onto your XIB in Interface Builder.
cell = [[[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil] objectAtIndex:0];
}
//*- Customize the cell, i.e., cell.myLabel.text = #"Text";
return cell;
}
Using this technique you can layout your cell with three labels, one for the number and one for the name of the song and one for the song time. Add a background image view for the border and color.
A simple way to get the song number in the table is to use the indexpath.
cell.myLabel.text = [NSString stringWithFormat:#"%i", indexPath.row + 1];

First visible UITableView rows not showing data when loading...but then do on scroll

I have a UITable which shows the 10 most recent images from a web service. Each row has its own image. When the UITable first loads in the viewcontroller it doesnt show the first 4 images in the rows (screen is blank). If I scroll down the last 6 images appear....then if I scroll back the first 4 images that were NOT there originally DO appear and everything looks the way I wanted it to initially. My guess is its something do with the way cells are reused.
Here is my tableView code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
}
[cell.contentView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
[cell.contentView addSubview:[self.photoList objectAtIndex:indexPath.row]];
return cell;
}
What solved my issue was adding the following line to my method that deals with streaming the photos from the Web API:
[_tableView reloadData];
I noticed that if I moved the Table View Cell up or down in the its Table View at the Storyboard that changed the position of the invisible row as well. So I solved the problem by setting the Table View Cell as hidden.

Issue with UITextField values in custom cell while scrolling fast ios

I have a simple table with custom cells each containing a textfield. In cellForRowAtIndexPath: I create and initialize each cell depending on indexPath.row:
case 0:
{
CellIdentifier = #"TextEditCell";
TextEditCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
[cell configureCellWithText: [self.valueArray objectAtIndex:0]
placeholder: #"value no.0"]
[cell performAction: #selector(saveValue0:)
forControlEvent: UIControlEventEditingDidEnd
inTarget: self];
return cell;
}
configureCellWithText:placeholder: sets text and placeholder of cell's textField.
performAction:forControlEvent:inTarget refers directly to textField and saves the value of textField to local array to be accurate when used again.
Problem occurs, when I scroll the table fast. Values from different cells copy to another cells and modify local array. I can't find out why it happens. Anyone have any idea? I can provide more code if needed.
This is happening because you are reusing the cells and configureCellWithText is being run after the cell is reused. To solve this you could:
Don't reuse cells - But this would really hurt your performance.
If you are running on 6.0 you can use tableView:didEndDisplayingCell:forRowAtIndexPath: to cancel the text setting action when the cell scrolls off screen.
You can create a flag in your custom cell class that you set when you dequeue a cell.
Edit
Because I do not know how your cell works. It is hard for me to give you anything more then a sudo code concept.
Here is my sudo code:
Tableview Cell for row...
- dequeue cell
- [cell cancel_previous_action]
- set new actions.

Assign tags correctly to cells and subviews of uitableview

Hey guys i've been stuck on this problem for 2 days in a row, so i'm asking if there is anybody out there that can give me a hand.
I have a tableview that is made up of 4 sections.
section 1 ->made up of just 1 row where its cell contains a subview which is a uiimageview
section 2 ->made up of 2 normal rows(just 2 plain simple cells with text in them)
section 3 -> made up of 1 normal row
section 4 -> made up of 1 row, where its cell contains a subview which is a uitextview that can contain dynamic text, so the uitextview's height and consequently the cells height varies depending on how much text is in the uitextview.
Here's the code to create this structure:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//create a nsstring object that we can use as the reuse identifier
static NSString *CellIdentifier = #"Cell";
//check to see if we can reuse a cell from a row that has just rolled off the screen
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//if there re no cells that can be reused, create a new cell
if(cell==nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
switch (indexPath.section) {
case 0:
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell.contentView addSubview:_viewForImageHeader];
break;
case 1:
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.numberOfLines = 0;
cell.textLabel.lineBreakMode = 0;
cell.textLabel.font = [UIFont fontWithName:#"AmericanTypewriter" size:16.0];
break;
case 2:
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.font = [UIFont fontWithName:#"AmericanTypewriter" size:16.0];
break;
default:
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell.contentView addSubview:_textViewForArticle];
break;
}
}
else{
NSLog(#"in else");
}
//here i fill in the 2 normal cells with text
return cell;
}
When the uitableview loads(in portrait mode) everything is perfect(image is in section 1, section 2 and 3 contain their correct text and in section 4 i have my dynamic text). But when i start to rotate the app, all the cells get mixed up. For example i find the contents of section3 in section 4 and vice versa.
I think this has to with the fact that i am not maybe reusing the cells correctly. Should i use tags, and if so, how can i implement the use of tags in the specific case?
Put switch case outside if condition - after the if and else
Yes, this is because of reusing cells. You have a few options here, but if you will never have more than the 5 cells in this tableView, by far the easiest and most optimum solution is to not reuse cells. In other words, instead of calling "dequeueReusableCellWithIdentifier", just allocate a new cell each time.
When you have many more cells, this would degrade performance, but if your cells are static and limited (as they appear to be), there is no real gain from trying to reuse cells.
If you DID have 4 "types" of cells and more rows (more dynamically allocated cells), the solution would be to subclass UITableViewCell for each of the 4 "types" of cells and then to call the correct one based on the section or whatever your criteria is.

Resources