iPhone UITableView Scrolling Slow With Cell ImageView - iphone

My app is scrolling very slow when I have Images set for each cell. I have tried using the SDImageWeb Project, but it still scrolls just as slow, and all the image views on the cell end up getting stretched around. Here is my code in the cell at row.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
RSSEntry *entry = [_allEntries objectAtIndex:indexPath.row];
//root path of image...used to check if image exists for this article
NSString *substring = #"http://316apps.com/ipreachersblog/wp";
NSRange textRange = [entry.articleImage rangeOfString:substring];
if(textRange.location != NSNotFound){
NSString *thearticleImage = entry.articleImage;
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:#"(?i)\\b((?:[a-z][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’]))" options:NSRegularExpressionCaseInsensitive error:NULL];
NSString *someString = thearticleImage;
NSString *oneurl = [someString substringWithRange:[expression rangeOfFirstMatchInString:someString options:NSMatchingCompleted range:NSMakeRange(0, [someString length])]];
NSURL *picimage = [NSURL URLWithString:oneurl];
UIFont *cellFont = [UIFont fontWithName:#"ArialRoundedMTBold" size:15];
UIFont *cellFont2 = [UIFont fontWithName:#"ArialRoundedMTBold" size:12];
NSData * urlData = [NSData dataWithContentsOfURL: picimage];
UIImage * imageweb = [UIImage imageWithData: urlData];
CGSize newSize = CGSizeMake(69, 69);
UIGraphicsBeginImageContext( newSize );
[imageweb drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CALayer * l = [cell.imageView layer];
[l setMasksToBounds:YES];
[l setCornerRadius:11];
[l setBorderWidth:2.0];
[l setBorderColor:[[UIColor blackColor] CGColor]];
cell.textLabel.text = entry.articleTitle;
cell.textLabel.font = cellFont;
cell.detailTextLabel.font = cellFont2;
cell.imageView.image = newImage;
cell.imageView.contentMode = UIViewContentModeScaleAspectFill;
}
else {
//loads when no featured image present
}
return cell;
}
Any ideas?

The problem is here
NSURL *picimage = [NSURL URLWithString:oneurl];
UIFont *cellFont = [UIFont fontWithName:#"ArialRoundedMTBold" size:15];
UIFont *cellFont2 = [UIFont fontWithName:#"ArialRoundedMTBold" size:12];
NSData * urlData = [NSData dataWithContentsOfURL: picimage];
UIImage * imageweb = [UIImage imageWithData: urlData];
CGSize newSize = CGSizeMake(69, 69);
UIGraphicsBeginImageContext( newSize );
[imageweb drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CALayer * l = [cell.imageView layer];
[l setMasksToBounds:YES];
[l setCornerRadius:11];
[l setBorderWidth:2.0];
[l setBorderColor:[[UIColor blackColor] CGColor]];
For every time you scroll the view 3 cells are downloading the images. Here you are resizing images which is not recommended
You need to set image in Lazy load like this
[cell.imageView setImageWithURL:picimage placeholderImage:[UIImage imageNamed:#"loadingPicture.png"]];
and every thing will be taken care by this. you can get this by importing this SDImageCache class, it will be available in this sample code at here

You are downloading the image from a remote source, so each time you load a new cell, the image gets downloaded and that will slow your application down, apple has a sample project on how to load the image asynchronously

Related

how to show images from web services in grid view

I am getting the images from the web services in list view but i want to show them in grid
view. As i am displaying the images in list view,In grid view how i can do this ? please help.this is how my code looks:-
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *CELLIDENTIFIER=#"CELL";
UITableViewCell *cell=nil;
if (cell==nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CELLIDENTIFIER] autorelease];
CGRect imageFrame = CGRectMake(2, 8, 80, 60);
NSURL *url = [NSURL URLWithString:[arrayListG objectAtIndex: [indexPath row]]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];
UIImageView *customImage = [[[UIImageView alloc] initWithFrame:imageFrame] autorelease];
customImage.image=img;
[cell.contentView addSubview:customImage];
}
return cell;
}
Better to use this awesome library for gridview
How to implement and integrate in project everything is documented on this link.check this out AQGridview
Gridview = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0, 320, 480)];//your frame
Gridview.backgroundColor=[UIColor clearColor];
int row=0;
int column=0;
int rows=4;
int cols=5;
for (int i=0; i<rows*cols; i++)
{
if((row%4==0)&&(row>0))
{
row=0;
column++;
}
else{
row++;
}
CGRect imageFrame = CGRectMake(row*80+10, column*60+10, 80, 60);//your imageview frame
NSURL *url = [NSURL URLWithString:[arrayListG objectAtIndex:i]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];
UIImageView *customImage = [[[UIImageView alloc] initWithFrame:imageFrame] autorelease];
customImage.image=img;
[Gridview addSubView:customImage];
}
[Gridview setContentSize:CGSizeMake(rows*90, cols*70)];
Gridview is your scrollview add it in IB or programatically as you desire in my case i have added it programatically. set content size and frame as per your requirement
Please modify your code as below.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *CELLIDENTIFIER=#"CELL";
UITableViewCell *cell=nil;
if (cell==nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CELLIDENTIFIER];
CGRect imageFrame = CGRectMake(2, 8, 80, 60);
UIImageView *customImage = [[UIImageView alloc] initWithFrame:imageFrame];
customImage.tag = 1;
[cell.contentView addSubview:customImage];
}
UIImageView *customImage = (UIImageView *)[cell viewWithTag:1];
NSURL *url = [NSURL URLWithString:[arrayListG objectAtIndex: [indexPath row]]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
customImage.image =img;
return cell;
}
You can try UIcollectionView a new control for ios,it is similar to UItabel view and easy to integrate.
Please have a look on these links
http://ashfurrow.com/blog/uicollectionview-example
http://www.raywenderlich.com/22324/beginning-uicollectionview-in-ios-6-part-12

How to load Images from NSMutableArray in UITableviewCell in iPhone?

I need to laod a image from NSMutableArray which is loaded from service url.I can retrieve the image tag from XML response.Now I want that image in a UITableViewCell
My array looks like this :
(
{
Image="46b6daca-3.png";
}
{
Image="9251bfe5-d.jpg";
}
)
How can I load each image in a seperate UITableViewCell ?
For creating a UILabel I knew it is like this :
NSMutableDictionary *d = (NSMutableDictionary *) [arr objectAtIndex:indexPath.row];
UILabel *line1=[[UILabel alloc]initWithFrame:CGRectMake(10, 68, 320,10)];
line1 .font=[UIFont fontWithName:#"arial" size:12];
[line1 setTextAlignment:UITextAlignmentLeft];
[line1 setText:[d valueForKey:#"Name"]];
line1.tag=113;
[cell addSubview:line1 ];
[line1 release];
How can I do it for UIImage?
UIImageView *img = [[UIImageView alloc]initWithImage:[ d objectForKey:#"Image"]];
[cell.contentView addSubView:img];
as per you code.. try this.
NSMutableDictionary *d = (NSMutableDictionary *) [arr objectAtIndex:indexPath.row];
UIImageView *img = [[UIImageView alloc]initWithImage:[ d objectForKey:#"Image"]];
img,frame = CGRectMake("Set frame")]
[cell.contentView addSubView:img];
[img release];
if you have images in your array then use direct array value as a image like bellow..
UIImageView *img = [[UIImageView alloc]initWithImage:[[arrData valueForKey:#"Image"] objectAtIndex:indexPath.row];
img.frame = SetFrameHere;//
[cell.contentView addSubView:img];
or also add as a cell imageview like bellow..
cell.imageView.image = (UIImage *)[[arrData valueForKey:#"Image"] objectAtIndex:indexPath.row];
Use the following code for setting the image:
UIImage *img = [[UIImage imageNamed:[d objectForKey:#"Image"];
cell.imageView.image = img;
Here d is your NSMutableDictionary

Why does my tableview break at the 4th entry?

This is the code I have. It works fine for the first 3 entries, then on the 4th entry, it starts showing the same cell content as other cells, despite the height of each cell being correct. Can anybody spot any problems that i'm not seeing here? The cell.textLabel.text is there purely for testing purposes, and comes back as the correct cell number, even if the contents of the cell aren't right. Since it's set at the same time as the content, this leads me to believe the problem is not in cellForRowAtIndexPath.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
JCell *cell = (JCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UIImageView *imageView;
if (cell == nil) {
cell = [[JCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
imageView = [[UIImageView alloc] init];
imageView.contentMode = UIViewContentModeCenter;
[cell addSubview:imageView];
}
UIImage *image = [self.mediaDelegate largeThumbnailForMediaAtIndex:indexPath.row];
imageView.frame = CGRectMake(0, IMAGE_SPACING, image.size.width, image.size.height);
imageView.image = image;
imageView.center = CGPointMake(cell.bounds.size.width / 2, imageView.center.y);
cell.textLabel.text = [NSString stringWithFormat:#"%i", indexPath.row];
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
int mediaHeight = [self.mediaDelegate heightForLargeThumbnailForMediaAtIndex:indexPath.row];
return mediaHeight + (IMAGE_SPACING * 2);
}
It's always going to be a JImage, because i haven't started on movie support yet.
-(UIImage *)largeThumbnailForMediaAtIndex:(int)index
{
id media = [self.media objectAtIndex:index];
if ([media isKindOfClass:[JImage class]]) {
JImage *image = media;
return [image getLargeThumbnail];
}
else if ([media isKindOfClass:[JMovie class]]) {
JMovie *movie = media;
return [movie getLargeThumbnail];
}
else {
return nil;
}
}
-(UIImage *)getLargeThumbnail {
if (self.largeThumbnail == nil) {
UIImage *originalImage = [UIImage imageWithContentsOfFile:self.originalImage];
UIImage *resizedImage = [originalImage imageScaledToFitSize:LARGE_THUMBNAIL_SIZE];
self.largeThumbnail = #"Generating";
dispatch_queue_t myQueue = dispatch_queue_create("LargeThumbnailQueue", 0);
dispatch_async(myQueue, ^{
NSString *filePath = [JImage writeImageToFile:resizedImage];
self.largeThumbnail = filePath;
});
return resizedImage;
}
else if ([_largeThumbnail isEqualToString:#"Generating"]) {
UIImage *originalImage = [UIImage imageWithContentsOfFile:self.originalImage];
UIImage *resizedImage = [originalImage imageScaledToFitSize:LARGE_THUMBNAIL_SIZE];
return resizedImage;
}
else {
NSString *filePath = self.largeThumbnail;
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
return image;
}
}
+(NSString *)writeImageToFile:(UIImage *)image {
NSData *fullImageData = UIImageJPEGRepresentation(image, 1.0);
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Images/"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDirectory = NO;
BOOL directoryExists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory];
if (directoryExists) {
} else {
[fileManager createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:nil];
}
NSString *retinaSupport;
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)] && [[UIScreen mainScreen] scale] == 2){
retinaSupport = #"#2x";
}
NSString *name = [NSString stringWithFormat:#"%#%#.jpg", [JMedia generateUuidString], retinaSupport];
NSString *filePath = [path stringByAppendingPathComponent:name];
[fullImageData writeToFile:filePath atomically:YES];
return filePath;
}
Any assistance or help with this problem is greatly appreciated.
when you reuse a cell (ie. you don't enter if (cell == nil) you don't have an imageView. imageView will be nil.
Add a tag to retrieve that imageView when you reuse your cells:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
JCell *cell = (JCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UIImageView *imageView;
if (cell == nil) {
cell = [[JCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
imageView = [[UIImageView alloc] init];
imageView.contentMode = UIViewContentModeCenter;
imageView.tag = 1234;
[cell addSubview:imageView];
}
imageView = [cell viewWithTag:1234];
UIImage *image = [self.mediaDelegate largeThumbnailForMediaAtIndex:indexPath.row];
imageView.frame = CGRectMake(0, IMAGE_SPACING, image.size.width, image.size.height);
imageView.image = image;
imageView.center = CGPointMake(cell.bounds.size.width / 2, imageView.center.y);
cell.textLabel.text = [NSString stringWithFormat:#"%i", indexPath.row];
return cell;
}
Shouldn't you rather do
UIImage *image = [self.mediaDelegate largeThumbnailForMediaAtIndex:indexPath.row];
cell.imageView.frame = CGRectMake(0, IMAGE_SPACING, image.size.width, image.size.height);
cell.imageView.image = image;
cell.imageView.center = CGPointMake(cell.bounds.size.width / 2, imageView.center.y);
?
(or at least, you should retrieve the imageView from the cell and not use what it looks to be a instance variable)
You're only allocating imageView to the cell if it goes into the
if (cell == nil)
block. So after the tableview has created a couple of instances, it will reuse them and you won't get an imageView added to it.
EDIT:
UIImageView *imageView; <------------ imageView is nil
if (cell == nil) {
cell = [[JCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
imageView = [[UIImageView alloc] init];
imageView.contentMode = UIViewContentModeCenter;
[cell addSubview:imageView];
}
UIImage *image = [self.mediaDelegate largeThumbnailForMediaAtIndex:indexPath.row];
// At this point, imageView is still nil - not been initialised to anything
imageView.frame = CGRectMake(0, IMAGE_SPACING, image.size.width, image.size.height);
imageView.image = image;
imageView.center = CGPointMake(cell.bounds.size.width / 2, imageView.center.y);

IPhone UITableView jerky when scrolling

I'm loading my table from an XML feed in to an array then creating the cells as the code below shows. It can be really jerky when loading sometimes. I thought that was just the images downloading when I scroll but I removed them to test and sometimes it was still jerky. Can't work out what I'm doing wrong!
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
const NSInteger BOTTOM_LABEL_TAG = 1002;
const NSInteger TEXT_FIELD_TAG = 1003;
UILabel *Labelcompanyname;
UILabel *Labeldistance;
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell =
[[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier]
autorelease];
const CGFloat LABEL_HEIGHT = 15;
int spaceSize;
if(currentType == #"categorySearch"){
spaceSize = 57;
}
else {
spaceSize = 34;
}
Labelcompanyname =
[[[UILabel alloc]
initWithFrame:
CGRectMake(
spaceSize + 2.0 * cell.indentationWidth,
0.5 * (tableView.rowHeight - 2 * LABEL_HEIGHT)+10,
tableView.bounds.size.width -
spaceSize - 20.0,
LABEL_HEIGHT)]
autorelease];
[cell.contentView addSubview:Labelcompanyname];
Labeldistance =[[[UILabel alloc]
initWithFrame:
CGRectMake(
spaceSize + 2.0 * cell.indentationWidth,
0.5 * (tableView.rowHeight - 2 * LABEL_HEIGHT)+40,
tableView.bounds.size.width -
spaceSize - 20.0,
LABEL_HEIGHT)]
autorelease];
if(currentType == #"categorySearch") {
[cell.contentView addSubview:Labeldistance];
}
Labelcompanyname.tag = BOTTOM_LABEL_TAG;
Labelcompanyname.font = [UIFont systemFontOfSize:[UIFont labelFontSize] - 2];
Labeldistance.tag = TEXT_FIELD_TAG;
Labeldistance.font = [UIFont systemFontOfSize:[UIFont labelFontSize] - 2];
cell.backgroundView = [[[UIImageView alloc] init] autorelease];
cell.selectedBackgroundView = [[[UIImageView alloc] init] autorelease];
cell.textLabel.numberOfLines=0;
}
else
{
Labelcompanyname = (UILabel *)[cell viewWithTag:BOTTOM_LABEL_TAG];
Labeldistance = (UILabel *)[cell viewWithTag:TEXT_FIELD_TAG];
}
PromotionObject *newObj1;
newObj1=[totalArray objectAtIndex:indexPath.row];
if(!newObj1.furtherURL){
Labelcompanyname.text =[NSString stringWithFormat:#"%#", newObj1.companyname];
Labeldistance.text =newObj1.distance;
}
else
{
Labelcompanyname.text =[NSString stringWithFormat:#"Load more results"];
Labeldistance.text =#"";
}
NSURL *Imageurl = [NSURL URLWithString:[NSString stringWithFormat:#"%#", newObj1.locImage]];
NSData *data = [NSData dataWithContentsOfURL:Imageurl];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];
if(currentType == #"categorySearch"){
cell.imageView.image = img;
} else if(currentType == #"fullSearch") {
cell.imageView.image = [UIImage imageNamed:#"newmap.png"];
} else {
cell.imageView.image = [UIImage imageNamed:#"business.png"];
}
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
Any help will be really appreciated
Tom
You definitely shouldn't do anything that blocks the UI thread for significant time while loading cells. E.g. NSData *data = [NSData dataWithContentsOfURL:Imageurl];.
I recommend loading your images into the data source in the background and reload/update the table/cells when the data has been downloaded. Would also be good to implement a cache for your images so you don't have to download them again everytime the cell is loaded.
If you need help with asynchronous image loading, search for that. Lot's of stuff on SO.
I guess you got your answer yourself. Your image loading blocks your UI from finishing the current cell request. tableView:cellForRowAtIndexPath: can't return until your image is fetched. I suggest you replace your image by an activity indicator and start to fetch your image in background. You might want to take a look at Concurrency Programming Guide

iPhone image memory leak

We have a code like this
NSData* imageData;
UIImage* imageForData;
UIImageView* imageView;
NSData* imageData;
UIImage* imageForData;
UIImageView* imageView;
CellWithId * cell = [[CellWithId alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier];
CGRect frame;
frame.origin.x = 5;
frame.origin.y = 0;
frame.size.height = 43;
frame.size.width = 52;
if ([[planDictionary objectAtIndex:indexPath.row] objectForKey:#"url"]!=[NSNull null]) {
imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[planDictionary objectAtIndex:indexPath.row] objectForKey:#"url"]]];
imageForData = [[UIImage alloc] initWithData:imageData];
imageView = [[UIImageView alloc] initWithImage:imageForData];
imageView.frame = frame;
[cell.contentView addSubview:imageView];
[imageData release];
[imageForData release];
}NSData* imageData;
UIImage* imageForData;
UIImageView* imageView;
//CellWithId *cell = (CellWithId*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// if (cell == nil) {
CellWithId * cell = [[CellWithId alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier];
//}
CGRect frame;
frame.origin.x = 5;
frame.origin.y = 0;
frame.size.height = 43;
frame.size.width = 52;
if ([[planDictionary objectAtIndex:indexPath.row] objectForKey:#"url"]!=[NSNull null]) {
imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[planDictionary objectAtIndex:indexPath.row] objectForKey:#"url"]]];
imageForData = [[UIImage alloc] initWithData:imageData];
imageView = [[UIImageView alloc] initWithImage:imageForData];
imageView.frame = frame;
[cell.contentView addSubview:imageView];
[imageData release];
[imageForData release];
}else {
//imageForData = [UIImage imageNamed:#"Plans-Default-image.jpg"];
imageForData = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Plans-Default-image" ofType:#"jpg"]];
imageView = [[UIImageView alloc] initWithImage:imageForData];
imageView.frame = frame;
[cell.contentView addSubview:imageView];
}
[imageView release];
I dont know what is the problem but imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[planDictionary objectAtIndex:indexPath.row] objectForKey:#"url"]]]; is a place which always shows memory leaks. Please help me to debug this issue.
You allocate two CellWithIdand never release it. It looks as though you do not properly implement this method. The cell returned in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
should be autoreleased:
CellWithId * cell = [[[CellWithId alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
// ...
return (UITableViewCell *)cell;
Also you should use dequeueReusableCellWithIdentifier:CellIdentifierproperly to have decent performance.