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
Related
I have tried following libraries for Image cache:
SDWebImage
UIImageView+AFNetworking
But still app getting Memory Warning, crashed and stuck while scrolling.
I have used UITableViewCell for display image.
Some of the images are 1.5 MB or more, So i am not sure whether this is the issue or anything else?
Please guide.
Any efforts from your side will be appreciated.
EDIT:
I have UITableViewCell for load UICollectionViewCell in UITableView:
Code for UITableViewCell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"homecell";
HomeViewCell *cell = (HomeViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"HomeViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSArray *arr=[[arrPsots objectAtIndex:indexPath.row ] valueForKey:#"PostImage"];
[cell setCollectionWithImageArray:arr];
return cell;
}
Code for UICollectionViewCell.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView1 cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = #"ScrollCollectionCell";
ScrollCollectionCell *cell = [collectionView1 dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
NSString *imgKey = (IS_IPAD?#"PostImage":#"PostImage");
NSString *strImage=[NSString stringWithFormat:#"%#",[arrImages valueForKey:imgKey]];
[cell.imgScroll setImageWithURL:[NSURL URLWithString:strImage] placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
if ([arrImages count]==1) {
self.pageControllPostImg.hidden=TRUE;
}
self.pageControllPostImg.hidden=TRUE;
self.pageControllPostImg.numberOfPages=[arrImages count];
return cell;
}
I had this problem in one project, where previous programmer create new cell every time and didn't use reusable cells.
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.
I am little confused regarding the use of dequeueReusableCellWithIdentifier method and how it works. I currently have a searchBar and two mutable Arrays (say filteredTableData and tableData) . Now I just realized that no matter what I do cell always returns nil. I also have a filter feature on my UITableView (using different arrays) however it seems to always return a nil. My question is when does dequeueReusableCellWithIdentifier return something ?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
MMTableCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MMTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.RowNo = indexPath.row;
cell.ImageAlbum.image = [self getMP3Pic:indexPath.row];
cell.table = self.tableViewObject;
}
NSString* sng = isFiltered ? [self.filteredTableData objectAtIndex:indexPath.row] : [self.tableData objectAtIndex:indexPath.row] ;
cell.labelSongName.text = [NSString stringWithFormat:#"%#", sng ];
return cell;
}
This is actually an optimization of displaying UITableView. Imagine that you have 1,000 of data to display and it does not make any sense to create 1,000 UITableViewCell in order to host each of your data. So, we use something called reusability that only a certain amount of cells will be used. When scrolling, it's not actually dealloc the invisible cells and create new cells. It's just move the existing cells around.
The identifiers are just used to identify different cells based on what you need. I might have multiple cell prototypes being used in one UITableView.
For your question, you will need to set up prototyped cells in the Interface builder. In the programmatical way, if we can not find the cell using dequeueReusableCellWithIdentifier method, then we create. But, you can take advantage of Interface Builder and it will always return cell.
dequeueReusableCellWithIdentifier is nothing but reusing the Cell whenever applicable. Initially cell is always nil. So, we check for cell==nil condition and we will create UITableViewCell first time. When u scroll the tableview then dequeueReusableCellWithIdentifier will be called to reuse the cell which is already created at First Time.
You can modify your code as below
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
MMTableCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[MMTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier] ;
}
cell.RowNo = indexPath.row;
cell.ImageAlbum.image = [self getMP3Pic:indexPath.row];
cell.table = self.tableViewObject;
NSString* sng = isFiltered ? [self.filteredTableData objectAtIndex:indexPath.row] : [self.tableData objectAtIndex:indexPath.row] ;
cell.labelSongName.text = [NSString stringWithFormat:#"%#", sng ];
return cell;
}
Try it..Hope it helps you..!
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;
}
My app contains some UITableViews, and cells contain several views. The cells also need to load images from server, so I use the open source tool named SDWenImage to asynchronously load images.
The problem is that UITableViews scroll smoothly in simulator, but not smoothly in iOS devices. Can anybody tell me why and how to solve the problem.
Following is some code related to the above problem:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
ItemTableViewCell *cell = (ItemTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = (ItemTableViewCell *)[[[NSBundle mainBundle] loadNibNamed:#"ItemTableViewCell" owner:self options:nil] lastObject];
}
GroupBuy *groupBuy = [tableArray objectAtIndex:indexPath.row];
cell.groupBuy = groupBuy;
[cell refreshData];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[[NSNotificationCenter defaultCenter] addObserver:cell selector:#selector(starAction:) name:#"StarAction" object:nil];
return cell;
}
Thank you very much.
for download images asynchronously use
http://www.markj.net/iphone-asynchronous-table-image/