Getting same data after clicking on uitableview cell - objective-c

I have and array of strings which is displayed in uitableview. When user taps on sort button the array is sorted and then i use [tableview reloaddata]. so that new sorted contents are displayed in table. but when i select particular cell the cell shows two texts overlapped on each other,the new sorted text and the text previously present in that cell.why is it happening so.
This is my code to display cells.
- (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] ;
}
UILabel * timeLabel = [[UILabel alloc]initWithFrame:CGRectMake(190, 0, 120, tableView.rowHeight)];
timeLabel.text = [[dataArray objectAtIndex:indexPath.row] time];
[cell.contentView addSubview:timeLabel];
return cell ;
}
This is my code for sorting.
-(void)sortByTime{
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"time"
ascending:NO] ;
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
dataArray = [sql getTableData]; // get data from sql file
sortedArray = [dataArray sortedArrayUsingDescriptors:sortDescriptors];
dataArray = [[NSMutableArray alloc]initWithArray:sortedArray];
[dataTableView reloadData];
}

there is a problem in your code. You are using reusable cells, and the problem is that you are not re using the views inside your cell. Particulary, timeLabel. You are creating a new timeLabel every time you use a cell, and when you reuse one, you add an adicional label to your cell, that is the possible reason for the ovelapped text.
For reuse the label, you should set a TAG number for the UILabel, and before create a new uilabel, check if the cell already have one.
I would replace the code:
UILabel * timeLabel = [[UILabel alloc]initWithFrame:CGRectMake(190, 0, 120, tableView.rowHeight)];
timeLabel.text = [[dataArray objectAtIndex:indexPath.row] time];
[cell.contentView addSubview:timeLabel];
with:
UILabel * timeLabel = [cell viewWithTag:55]
if(!timeLabel) {
timeLabel = [[UILabel alloc]initWithFrame:CGRectMake(190, 0, 120, tableView.rowHeight)];
timeLabel.tag = 55;
[cell.contentView addSubview:timeLabel];
}
timeLabel.text = [[dataArray objectAtIndex:indexPath.row] time];
The value for the tag number is up to you, i just use 55 as an example. Good Luck!

as you want a customized cell and you just put new subviews in cell every time this is happend you have to use customized cell created in deferent nib and use it to display your data
just make new nib and load it from new nib so you got proper data
or can check is there any subview in cell's contentView then remove them first and then add new created subview

Related

UITableView imageView Shows Image Where An Image Should Not Be After Scrolling

I have a uitableview with a list of people in it. some records have an image and some records do not. If i scroll down through the list it appears correct but if i scroll back up then an image of another person starts to show on other people's cell row where an image should not be. Here is my code for cellForRowAtIndexPath
// START CELL LABELLING FOR TABLE VIEW LIST //
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
Person *person = [arrayOfPersons objectAtIndex:indexPath.row];
NSString *personPhoto = person.personPhoto;
NSString* imgPath = [docPath stringByAppendingPathComponent:
[NSString stringWithFormat:#"%#", personPhoto] ];
if ([[NSFileManager defaultManager] fileExistsAtPath:imgPath]){
NSLog(#"FILE EXISTS");
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(240, 0, 67, 67)];
imageView.image = [UIImage imageWithContentsOfFile:imgPath];
imageView.contentMode = UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:imageView];
}else{
NSLog(#"Does Not Exist");
}
cell.textLabel.text = person.personName;
return cell;
imageView = nil;
personPhoto = #"";
imgPath = #"";
}
// END CELL LABELLING FOR TABLE VIEW LIST //
The reason this is happening is because table cells get re-used.
When you use [tableView dequeueReusableCellWithIdentifier:CellIdentifier], you get back a cell that has already been shown in your table view (for a different index path). You may have already added an image view to this cell for the Person at this previous index path, and nowhere do you remove this image.
Therefore, when the current Person doesn't have a photo, the previous image will remain visible in the cell.
I would recommend creating your own UITableViewCell subclass and adding a UIImageView to it, so that you can easily get a reference back to the image view (or you could use a view tag, if you prefer).
Either way, you need to remove the image view/set the image to nil when the person does not have a photo.

UITableView overlaps on scrolling

In my Storyboard I've got a table view.
I'm filling that table view using data loaded from a JSON file (loaded in viewDidLoad).
In my UITableView I did set "Prototype Cells" to 1 so I can easily select a Accessory.
My Prototype Cell has a Seque to a new View which needs to show the details of the selected item.
I'm filling my Cells programmatically using this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *videoTableIdentifier = #"VideoCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:videoTableIdentifier];
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:videoTableIdentifier];
UILabel * title = [[UILabel alloc] initWithFrame:CGRectMake(40,5, 240,20)];
[cell addSubview:title];
[title setText:[[videos objectAtIndex:indexPath.row] objectForKey:#"title"]];
UILabel * detail = [[UILabel alloc] initWithFrame:CGRectMake(40,28, 100,10)];
[cell addSubview:detail];
[detail setText:[NSString stringWithFormat:#"Year: %#", [[videos objectAtIndex:indexPath.row] objectForKey:#"year"]]];
[cell addSubview:[[UIImageView alloc] initWithImage:[UIImage imageNamed:[[videos objectAtIndex:indexPath.row] objectForKey:#"image"]]]];
return cell;
}
When I start scrolling the following happens:
So I started searching for a solution and found that I had to set: dequeueReusableCellWithIdentifier:videoTableIdentifier to "nil".
While I did that, this solved my problem, BUT now me Prototype Cell Accessory and Seque are gone so I can't navigate to the next view anymore.
I couldn't find a solution for this on the internets so I decided to ask this.
Would be awesome if someone could help.
Your problem is that every time you re-use a cell, you are adding new subviews to it, so if you have a cell with some labels, and you reuse it and add more labels, all of them appear overlaped.
I suggest you to make your own custom UITableViewCell with labels on it, and just change the value of the labels every time.
if (!title){
title = [[UILabel alloc] initWithFrame:CGRectMake(40,5, 240,20)];
[cell addSubview:title];
}
[title setText:[[videos objectAtIndex:indexPath.row] objectForKey:#"title"]];
Previous answer author is right. It could be better to use your own subclass of UITableViewCell.
I don't see any memory release. Are you using automatic reference counting?

How to get index of every item in an array Objective-C

For an iPhone app I am developing I need to assign custom uitableviewcell images based on the integers of arbitrary items in an array. I noticed while doing some testing that indexPath of row only returns indices for the view shown, so basically I need to know how to take an array, of arbitrary size, let's say right now it has 10 items, and those 10 items are in a table, each item a cell, I need each item to have an index like item 1 is index 0, item 2 is index 1 and so on. So my code would read, if the index == 0, then display this image in the cell, if the index != 0 then display another. I tried that but like I said if I scrolled to the bottom of my tableview it would reassign whichever table item is at the top of the view to 0, so as I scrolled the images kept changing. So basically i need help assigning the images based on an index in my array rather than on the index of the table.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:MyIdentifier] autorelease];
}
cell.detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
cell.detailTextLabel.numberOfLines = 1;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
NSString *title =[[stories objectAtIndex: indexPath.row] objectForKey: #"summary"];
NSString *title2 =[[stories objectAtIndex: indexPath.row] objectForKey: #"title"];
NSString *dayOfMonthString = [title substringWithRange: NSMakeRange(2, 2)];
int dateChooser = [dayOfMonthString intValue];
NSString *monthString = [title substringWithRange: NSMakeRange(0, 2)];
int monthChooser = [monthString intValue];
cell.textLabel.text =title2;
cell.imageView.image =
[UIImage imageNamed: [NSString stringWithFormat: #"cal%d.png", dateChooser]];
if (monthChooser == 1 && (INDEX COMPARISON CODE???){
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Jan1.png"]];
[cell setBackgroundView:myImageView];
}
Your problem is not getting the right index for the right cell. The row property of the indexPath do correspond to the index of the cell in the whole list of cells, not the index of the visible cells only, so exactly as you expected initially.
I bet your problem is that you don't use the reuse mechanism of UITableViewCells correctly
.
When you scroll in your TableView, UITableViewCells that are not on screen anymore are "recycled" and reused to display new cells onscreen, in order to avoid too much allocations and useless initializations that would else slow down the scrolling of your tableView.
The correct code pattern for returning a cell is the following:
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
// Try to retrieve a previously created cell that is not used anymore
// That's the "recycling" part, we try to reuse a cell instead of creating a new one if possible
UITableViewCell* cell = [tableView dequeueCellWithIdentifier:#"myIdentifier"];
if (cell == nil)
{
// We failed to recycle a previously created cell, so we have no choice to allocate a new one
cell = [[[UITableViewCell alloc] initWithStyle:... reuseIdentifier:#"myIdentifier"] autorelase];
// As we just created the cell, we configure everything that will be common to every cell
// and that won't change even if the cell is reused later when you scroll
// e.g. text color, text font, accessoryType, ...
cell.textLabel.textColor = [UIColor blueColor];
...
}
// Now we got here either with a brand new cell that have just been created…
// … or after reusing an old cell that were not onscreen and has been recycled
// So THIS IS THE PLACE to configure everything that is SPECIFIC to each cell
// namely cell text, especially
cell.textLabel.text = [yourDataArray objectAtIndex: indexPath.row];
return cell;
}

adding different UILabel to each cell in UITableView

I'm adding different text to each cell in UITableView. However when I do that, test is displayed in every cell except for the first one..So if theres an array with 9 numbers between 1 to 9, 1 is displayed in the second cell, 2 is displayed in the third cell and respectively. There's nothing shown in the first cell fromHeres the codes
// Customize the appearance of table view cells.
- (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] autorelease];
cell = [self getCellContentView:CellIdentifier];
}
if (indexPath.row == 0) {
NSLog(#"hi");
}
//add another textfield
NSString *path = [[NSBundle mainBundle] pathForResource:#"Rankvalue" ofType:#"plist"];
NSMutableArray* rank = [[NSMutableArray alloc] initWithContentsOfFile:path];
NSString *rankValue = [rank objectAtIndex:indexPath.row];
UILabel *rankLabel = (UILabel *)[cell viewWithTag:1];
rankLabel.text = rankValue;
[rankLabel setFont:[UIFont fontWithName:#"austin power" size:[#"40" intValue]]];
CGRect labelFrame = CGRectMake(220,70,50,40.0);
[rankLabel setFrame:labelFrame];
// Configure the cell(thumbnail).
cell.textLabel.text = [self.stars objectAtIndex:indexPath.row];
NSString *path2 = [[NSBundle mainBundle] pathForResource:#"Filename" ofType:#"plist"];
self.filename = [[NSMutableArray alloc] initWithContentsOfFile:path2];
cell.imageView.image = [UIImage imageNamed:[self.filename objectAtIndex:indexPath.row]];
//transparent cell
cell.backgroundColor = [UIColor clearColor];
[rankLabel release];
[rankValue release];
return cell;
}
And this is the code for the subview of the cell
- (UITableViewCell *) getCellContentView:(NSString *)cellIdentifier {
CGRect CellFrame = CGRectMake(0, 0, 320, 65);
CGRect Label1Frame = CGRectMake(17,5,250,18);
UILabel *lblTemp;
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CellFrame reuseIdentifier:cellIdentifier] autorelease];
lblTemp = [[UILabel alloc] initWithFrame:Label1Frame];
[lblTemp setFont:[UIFont fontWithName:#"Arial-Bold" size:15]];
lblTemp.tag = 1;
lblTemp.backgroundColor=[UIColor clearColor];
lblTemp.numberOfLines=0;
[cell.contentView addSubview:lblTemp];
return cell;
}
initWithFrame:reuseIdentifier: has been deprecated for initWithStyle:reuseIdentifier:
You should create one of the standard styles.
Set the values you want (font, etc.) on cell creation, not on refresh. Frame of text field is the same. And background color.
You really don't want to reload that plist (oh, there's two of them!) every time you refresh a cell! Load it once in another method and cache it as an ivar.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// create and set up all the layout attributes of the cell
// it should be auto released
// which should include a call like the following, or loading a cell from a nib
// cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
// reuseIdentifier:CellIdentifier];
// [cell autorelease];
}
// the only thing that should happen here is setting the data values
// into the cell!!!!!! All these values should be loaded once and
// kept as "model state" by the controller. Do not create an image
// each time through, do not load an entire plist to access one item
// each time through
rankLabel.text = rankValue;
cell.textLabel.text = [self.stars objectAtIndex:indexPath.row];
cell.imageView.image = [self imageAtRow:indexPath.row];
}
If the image your displaying is different for each cell, using imageNamed: is not appropriate. If there's 2 or 3 images that indicate type of cell that will each be used a lot, imageNamed: is likely preferable. imageWithContentsOfFile: is your other option, you'll need to build the full path
Try switching this:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
//cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell = [self getCellContentView:CellIdentifier];
}
for this:
UITableViewCell *cell=[self getCellContentView:CellIdentifier];
Not saying it will work, but just give it a shot. Also, do this inside your getCellContentView:
[lblTemp release]
Or you will have a leak.

objective-c: [self.tableview reloadData] reloads data but doesnt clear older cells

i'm working on a tableview and i am newbie in dynamically creating cells (i used to create them with IB and then link them to their tableviewcell controller etc..).
Everything works great and recpected arrays are updated properly but when i fire [self.tableview reloadData] the program just redraws new values over old cells. for example if there "TEST CELL" value in a uilabel inside a cell, when i update the data to "CELL TEST" and fire the reloadData, the uilabel looks like there are two labels on top of each other and both values are visible. (its like creating two uilabel with exact same location and same size and setting their values)
and this event happens everytime i fire reloadData, with each reload, the program looks like its adding another uilabel on top of the older one. heres my 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] autorelease];
}
UILabel *lblText1 = [[UILabel alloc] initWithFrame:CGRectMake(30, 5, 130, 30)];
lblText1.adjustsFontSizeToFitWidth = YES;
lblText1.backgroundColor = [UIColor clearColor];
lblText1.text = [lblText1Array objectAtIndex:indexPath.row];
[cell addSubview:lblText1];
[lblText1 release];
if(indexPath.row<3)
{
UILabel *lblText2 = [[UILabel alloc] initWithFrame:CGRectMake(170, 5, 130, 30)];
lblText2.adjustsFontSizeToFitWidth = YES;
lblText2.backgroundColor = [UIColor clearColor];
lblText2.text = nil;
lblText2.text = [spParameters objectAtIndex:indexPath.row];
[cell addSubview:lblText2];
[lblText2 release];
}
else if(indexPath.row==3){
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(170, 7, 130, 30)];
textField.adjustsFontSizeToFitWidth = YES;
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.placeholder = #"please insert value";
textField.textAlignment = UITextAlignmentCenter;
textField.delegate = self;
textField.text = [spParameters objectAtIndex:indexPath.row];
[cell addSubview:textField];
[textField release];
}
else if(indexPath.row == 4)
{
UISwitch *gSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(170, 7, 130, 30)];
[gSwitch setOn:FALSE];
[gSwitch addTarget: self action: #selector(switchValueChanged:) forControlEvents:UIControlEventValueChanged];
[cell addSubview:gSwitch];
[gSwitch release];
}
// Configure the cell...
return cell;
}
im releasing the components after i adding them to subviews, and i am thinking about if theres something wrong with the reuseidentifier...
Thanx for helping.
It looks as though you're populating a detail view with a fixed number of cells, so you should consider creating the instances statically, for example in viewDidLoad or in Interface Builder. You could store each cell in a separate instance variable, and just return the one that corresponds the current row each time tableView:cellForRowAtIndexPath: is called.
If you create the cells programmatically, add whatever subviews you need at that time. Otherwise, as I mentioned, you could do that in Interface Builder, which often makes it easier to set up the details of controls such as text fields. Note though that UITableViewCell already contains an instance of UILabel, so adding one yourself is redundant. Instead, just access the cell's textLabel property to get its label.