Loading photos in uitableview asynchronously - ios

In my app I load cell's photo right in cellforrowatindexpath, but it takes main thread for a long period, and when I scroll, my app stops for a while.
What should I do? If I add async thread it would call it every time I scroll and there could be 2 or more equal photo loading requests, and this is not good... Is there any idea without spaghetti coding?

Try SDWebImage framework
https://github.com/rs/SDWebImage
Sample Code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier];
}
// Here we use the new provided sd_setImageWithURL: method to load the web image
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:#"Get each url from array and set it here using indexpath.row"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}
It supports variety of features like caching etc.

Related

Tableview Images doesn't load, but at times appears when scrolling

Tableview Images doesn't load, but at times appears when i scroll the page or else appears when i click on a cell.
NB: I am using SDWebImage for lazy loading purposes.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *c = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (c == nil)
{
c = [[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:#"cell"];
}
[c.imageView1 setImageWithURL:[NSURL URLWithString:#"http://www.worldweatheronline.com/images/wsymbols01_png_64/wsymbol_0008_clear_sky_night.png"] placeholderImage:[UIImage imageNamed:#"pl.png"]];
Better use SDWebImage+ActivityIndicator, it will show you the activity indicator when the image is downloading.
Dowload link - SDWebImage+ActivityIndicator
Replace as this method- [c.imageView1 setImageWithURL:[NSURL URLWithString:temp1] placeholderImage:[UIImage imageNamed:#"emptypic"] usingActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];

How to make UITableView load data fast

In my app, the tableView data is loading very slowly. I am getting image from JSON for showing it in the UITableViewCell.
First, the UITableView is empty and only after 15 sec, the data shows up. I want the data to load at the same time when tableView starts loading.
Please give me any idea about my problem. Here is some relevant code.
- (void)viewDidLoad
{
NSURL * url=[NSURL URLWithString:#"http://www.educarelive.com/SaveDollar/rest/classifieds/getTestImage"];
NSURLRequest *req=[NSURLRequest requestWithURL:url];
con1=[NSURLConnection connectionWithRequest:req delegate:self];
if(con1)
{ NSLog(#"Connected");
webData=[[NSMutableData alloc]init];
NSLog(#"Connected2");
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.thumbnailImageView.image = [secondarray objectAtIndex:indexPath.row]; cell.nameLabel.text = [titlearray objectAtIndex:indexPath.row];
}
You could use SDWebImage which will make service call in background and let u update the UI(the cell.nameLabel) ,and for ur that image part this will update depending on connection speed. So this way ur user will be able to see nameLabel and image(a bit later - depending on speed of net) and load ur tableView quicker.
Also no need to call reload when ur getting image. SDWebImage code be like this:-
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Here we use the new provided setImageWithURL: method to load the web image
[cell.thumbnailImageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.nameLabel.text = [titlearray objectAtIndex:indexPath.row];
return cell;
}
Here is link for SDWebImage for your reference.
I strongly agree with walle84. And Also u can have UIActivityIndicator while processing Image to Your ImageView.
For this You can use again SDWebImage 's category. And here is the link for this UIActivityIndicator-for-SDWebImage

UITableView Scrolling Performance with Custom UITableViewCells

Requirement : To Display upto 9 Datapoints in a single Custom TableViewCell with 2 UILabels,4 UIButtons and 3 UIImages.
Problem Statement:Scrolling with the Custom UITableViewCell is not smooth with these UIImages and UIButtons added as subviews. There are approximately 500 rows in the UITableView.
If the problem is in number of view on one cell.
Try to set shouldRasterize property of cell's layer to YES.
yourCell.layer.shouldRasterize = YES;
yourCell.layer.rasterizationScale = [UIScreen mainScreen].scale;
But remember that all animated views such as UIActivityIndicatorView will force the cell to redraw it's content on each frame.
I use this Library which is just perfect
SDWebImage
You just need to #import <SDWebImage/UIImageView+WebCache.h> to your project, and you can define also the placeholder when image is being downloaded with just this code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the new provided setImageWithURL: method to load the web image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}
It also cache downloaded images and gives you great performance.
Hope it will help you!

UITableViewCell Doesn't display loaded data but displays it when selected

I am facing a weird issue and I am sure I am doing something wrong. In my UITableViewController class I have a function as follows:
-(void)EERefreshView
{
NSLog(#"App delegate requested the view be refreshed");
[self loadEventsFromDB];
for(int a=0;a<eventsList.count;a++)
{
DB_EEEvent *event = (DB_EEEvent*)eventsList[a];
UITableViewCell *cell =
[self.tableView dequeueReusableCellWithIdentifier:#"Cell"];
//NSLog(#"CellID %#", cell.reuseIdentifier);
//get references to the UI components
UILabel *lblTitle = (UILabel*)[cell.contentView viewWithTag:5];
UILabel *lblDate = (UILabel*) [cell.contentView viewWithTag:6];
UIImageView *imgEvent = (UIImageView*)[cell.contentView viewWithTag:7];
//set values
lblTitle.text = event.name;
lblDate.text = [NSString stringWithFormat:#"%# - %#",
event.startdate,event.enddate];
AppDelegate *del = [AppDelegate sharedAppDelegate]; //need this to get the BaseURL
// Here we use the new provided setImageWithURL: method to load the web image
NSString * imageURL =[[NSString alloc] initWithFormat:#"http://%#%#",del.api.BaseURL,event.logo];
NSString* webStringURL = [imageURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:webStringURL];
[imgEvent setImageWithURL:url placeholderImage:[UIImage imageNamed:#"placeholder.png"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType) {
//do somethign when image call completes
}];
[eventsListCells addObject:cell];
if(a == selectedEvent)
{
}
}
dispatch_async(dispatch_get_main_queue(), ^{
[tblEventsList reloadData];
});
}
This function loads an array with UITableViewCell objects which is then used later on by
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Configure the cell data
NSLog(#"IndexPathRow: %d", indexPath.row);
UITableViewCell *cell = (UITableViewCell*)eventsListCells[indexPath.row];
return cell;
}
However when the cell is loaded lblTitle and lblDate have no text displaying in them. But when I tap on a cell it then displays the text in the labels. So this means that the data is there but its not being refresh when initially created. I suspect this might have something to do with threads but I am not an expert on the subject and would appreciate any help that I can get.
I see what is bothering you and why you created this method, but you don't need it. The only reason why you need back thread is your image loading so that should be thrown in bkg. thread and the rest of the code should be in -
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath.
U really don't need to pre create cells, and U cant cause they are reusable. For example if you have 50 elements in eventsList and room for only 5 cell on your screen you cant create 50 cells cause the code will create only 5+1 and reuse them as they appear on the screen, so every element of your eventsList will use one of those 5 cells and on the other side every cell will be a host for 10 different elements from your eventsList array. So as you can see your code doesn't make much sense...
The second function you mentioned in your question is the function that is called to populate the table with data. When you call [tblEventsList reloadData]; your app just calls the (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method. So this method needs to be outputting data back to the table. A very simple example is below. Also, make sure your table delegate and data source are set.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Configure the cell.
cell.textLabel.text = [self.your_data_source objectAtIndex:[indexPath row]];
return cell;
}

Images getting mixed up when scrolling in a UITableView

Hi found the answer here: Images getting mixed up in a UITableView - XML parsing
I'm parsing an XML file with links to images which I'm putting into a UITable. For some reason the pictures are getting completely mixed up when I scroll down in the table. Here's the code I'm using for my UITable:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
Tweet *currentTweet = [[xmlParser tweets] objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
CGRect imageFrame = CGRectMake(2, 8, 40, 40);
customImage = [[UIImageView alloc] initWithFrame:imageFrame];
[cell.contentView addSubview:customImage];
}
NSString *picURL = [currentTweet pic];
if (![picURL hasPrefix:#"http:"]) {
picURL = [#"http:" stringByAppendingString:picURL];
}
customImage.image = [UIImage imageWithData:[NSData dataWithContentsOfURL: [NSURL URLWithString:picURL]]];
return cell;
}
Any idea what I'm doing wrong? Any help is seriously appreciated. Thx!
Its because you are dequeueing reusable cells. It is recycling a cell that had a previously used image in it.
I noticed that you are setting the image in the same if block that you are initializing the cell. If I were you I'd move [cell.contentView addSubview:customImage]; to right before your return statement. This way when it recycles a dequeued cell, it won't have an image in it.
Are the images being downloaded from the web?
If so then the delay in downloading the images will be causing this. You'll need to do it in a multi threaded way.
Take a look at this example...
Question about Apple's LazyTableImages sample - Doesn't behave exactly like the app store
There are also many tutorials online about lazy loading with images and UITableViews.

Resources