UITableView imageView Shows Image Where An Image Should Not Be After Scrolling - objective-c

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.

Related

Font size in UITextView change unexpectedly

I have a table view with several table view cell. The table view cell consists of title (using UILabel), picture (using UIWebView) and summary (using UITextView).
When I use UIImage for the picture, everything runs well. But then, I decided to display the pic by using resized UIWebView instead of UIImage. Some of the summary in the UITextView change unexpectedly.
When I scrolled the table, the problem will sometimes disappear. But it can randomly appear again on different table view cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
TableViewCell *cell = (TableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = table;
self.table = nil;
}
//Configure the cell...
Article *article = [_articleRepository fetchArticleById:[articleIds objectAtIndex:indexPath.row]];
cell.headline.text = article.articleTitle;
// Remove html tag
NSString *substringContent = [self stringByStrippingHTML:article.articleContent];
cell.content.text = substringContent;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
ImageRepository *imageRepository = [[ImageRepository alloc]init];
Image *image = [imageRepository fetchImageById:article.articleImage];
NSMutableString *mutUrl = [[NSMutableString alloc]initWithString:image.imageUrl];
[mutUrl insertString:#"_thumb" atIndex:[mutUrl length]-4];
NSString *stringUrl = [[NSString alloc]initWithString:mutUrl];
NSString *htmlImage = [NSString stringWithFormat:#"<html><head><style type=\"text/css\">body{margin: 0; padding: 0;}</style></head><body><img src=\"%#\"></body></html>", stringUrl];
[cell.image loadHTMLString:htmlImage baseURL:nil];
return cell;
}
It could be due to reuse of cells in the tableview that make ur problem appear randomly across cells. Would help if you posted code of what you've done.
EDIT: Try changing ur portion of the code to the one given below.
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
Some questions:
1. Why are you doing cell = table & self.table = nil ?

Reloading searchResultsTableView

I have, in my main tableView, some custom cells (cells with an imageView, basically).
The imageView is set only if a value on my plist is false. Then, when it's true, the imageView is nil.
Basically when the user enters the detailView, the value is set to YES and the cell.imageView is nil.
And it's okay, it works
I'm using a searchDisplayController, when i search for something that has a cell.imageView, going into the detailView and then coming back to the searchResultsTable, the cell has still the image, while it shouldn't, but the main tableView has the correct cell (so, with no image).
I thought that it could depend on searchResultsTableView, but i'm not sure.
I tried with
[self.searchDisplayController.searchResultsTableView reloadData];
with no effect.
How could i reload the searchResultsTableView so that it shows the right cells, those with the image and those that don't have the image anymore?
Any help appreciated!
EDIT
This is my cellForRowAtIndexPath method:
- (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];
}
NSArray *rows;
if (tableView == self.searchDisplayController.searchResultsTableView) {
rows = filteredList; //for search
} else {
NSDictionary *section = [localSortedTips objectAtIndex:indexPath.section];
rows = [section objectForKey:#"Rows"];
}
NSDictionary *item = [rows objectAtIndex:indexPath.row];
cell.textLabel.text = [item objectForKey:#"name"];
if ([[item valueForKey:#"isRead"] boolValue] == NO) {
cell.imageView.image = [UIImage imageNamed:#"unread.png"];
} else {
cell.imageView.image = nil;
}
cell.textLabel.font = [UIFont boldSystemFontOfSize:15.0];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
return cell;
}
If I understood you right, then you can have a workaround but searching again with the same search string:
if (self.searchDisplayController.active) {
self.searchDisplayController.searchBar.text = self.searchDisplayController.searchBar.text;
}
put it in viewWillAppear: or viewDidAppear: which will be called each time the view is shown up (eg. you go back from the detail view to your search view). And reloading the data in this place would be nice too, to get the right data (for example if you marked the cell as read like in your sample code)
Just [self.tableView reloadData]; and not the searchResultsTableView (it will be automatically use the updated data after the new search)
It sounds as if perhaps your cells are being recycled and not reset properly. UITableView uses view recycling, so it's important that if you do something such as set an image you make sure it is explicitly set even when their isn't an image to display.
If you share your cellsForRowAtIndexPath code you might be able to get some more help.

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;
}

dequeueReusableCellWithIdentifier causing problem on UIImageView

I am loading a tableView with 500 rows. The problem is that in each row there is a different picture. Or when I use dequeueReusableCellWithIdentifier, those picture are just loaded again and the real pictures I am looking for are not shown (I just have about 8 different pictures : the first 8 loaded on my screen). If I don't use the dequeureReusableCellIdentifier, all the picture are loaded. But will it slow the displaying ?
Here is the code (I am currently working on getting the picture cached) :
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CustomCellIdentifier = #"CustomCellIdentifier";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier: CustomCellIdentifier];
NSLog(#"Launching CellForRowAtIndexPath");
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell"
owner:self options:nil];
if ([nib count] > 0) {
cell = self.profilCell;
} else {
NSLog(#"failed to load CustomCell nib file!");
}
}
NSUInteger row = [indexPath row];
NSDictionary *rowData = [listProfils objectAtIndex:row];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:nameValueTag];
nameLabel.text = [rowData objectForKey:#"name"];
NSString *finalId = [NSString stringWithFormat:#"http://graph.facebook.com/%#/picture", [rowData objectForKey:#"id"]];
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:finalId]]];
[profilPic setImage:image];
return cell;
}
THank you ! :)
It looks like you have an ivar profilPic that is probably an outlet that gets linked when you load a new cell nib. If that's the case, it's always going to point to the last cell that you loaded and won't change the image in the cell you've just dequeued. Instead of using an outlet, you might want to identify that custom view some other way, like a tag. So, if you set the profile pic UIImageView's tag to 100, for example, in Interface Builder, you could do something like this:
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:finalId]]];
UIImageView* cellImageView = (UIImageView*)[cell viewWithTag:100];
[cellImageView setImage:image];
Also, I just want to point out that -dataWithContentsOfURL: will load the URL synchronously on the main thread. If you're testing in the simulator on a fast connection, this will work pretty well. If, however, you are on 3G in SoHo on Friday afternoon... your app will probably start being killed by the watchdog.
I just met this problem, my solution is hold a private NSMutableDictionary to store the new images which asynchronously loaded from web before, use my identifier as key, UIImageView as Object (because I need to load the icon image first), when web image is ready, change it, When tableView dequeue return's null, I can read the original UIImage from my own cache.
Something like this.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
UIImageView *imageView = [thumbnailCache objectForKey:identifier];
if (!imageView) {
cell.imageView.image = [UIImage imageNamed:#"icon.png"];
[thumbnailCache setObject:cell.imageView forKey:identifier];
} else {
cell.imageView.image = imageView.image;
}
}
When I load the actual image from web, refresh the thumbnail cache.
asynchronously_load_image_from_web(^(UIImage *image) {
cell.imageView.image = image;
[thumbnailCache setObject:cell.imageView forKey:identifier];
});

Customize table cells to display images

I am intending to add images (via URL string) into a table view. However, the photo images are not displayed in the table. Below is my code for this.
- (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];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectZero];
imageView.tag = kImageValueTag;
[cell.contentView addSubview:imageView];
[imageView release];
}
// Configure the cell...
NSUInteger row = [indexPath row];
Photo *thisPhoto = [self.thisArray objectAtIndex:row];
UIImageView *thisImageView = (UIImageView *)[cell.contentView viewWithTag:kImageValueTag];
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: thisPhoto.imageURL]];
NSLog(#"URL: %#",thisPhoto.imageURL);
thisImageView.image = [UIImage imageWithData:imageData];
return cell;
}
All my images are of different sizes. How do I make the table show the images based on their sizes?
The below blog posts could guide you for downloading the images in cells from internet.
MHLazyTableImages – Efficiently Load Images for Large Tables
HJCache: iPhone cache library for asynchronous image loading and caching.
As you asked for the cell size based on your images, i would recommend you to show all the images in the predefine rectangle and would be same for all.
Although you could alter the size of each the cell based on the images size but it would decrease the performance of your UITableView.