IPhone UITableView jerky when scrolling - iphone

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

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

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

Objective-C: First item of NSArray sometimes is missing

I have and NSArray with 5 string elements, populating an UITableView of my iPhone App.
Everything works fine, but sometimes the first string of my array is missing and I can't figure out why.
Here is my code:
arrayList = [[NSArray alloc] initWithObjects: #"My First String",
#"My Second String",
#"My Third String",
#"My Forth String",
#"My Fifth Sring",
nil];
The element that sometimes just doesn't show up is My First String
Actually I'm using this sample code from Cocoa With Love. Thanks guys for helping me!
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
#if USE_CUSTOM_DRAWING
const NSInteger TOP_LABEL_TAG = 1001;
// const NSInteger BOTTOM_LABEL_TAG = 1002;
UILabel *topLabel;
// UILabel *bottomLabel;
#endif
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
//
// Create the cell.
//
cell =
[[[UITableViewCell alloc]
initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier]
autorelease];
#if USE_CUSTOM_DRAWING
UIImage *indicatorImage = [UIImage imageNamed:#"image1.png"];
cell.accessoryView =
[[[UIImageView alloc]
initWithImage:indicatorImage]
autorelease];
const CGFloat LABEL_HEIGHT = 22;
UIImage *image = [UIImage imageNamed:#"image2.png"];
//
// Create the label for the top row of text
//
topLabel =
[[[UILabel alloc]
initWithFrame:
CGRectMake(
image.size.width + 2.0 * cell.indentationWidth,
0.5 * (aTableView.rowHeight - 1.3 * LABEL_HEIGHT),
aTableView.bounds.size.width -
image.size.width - 4.0 * cell.indentationWidth
- indicatorImage.size.width,
LABEL_HEIGHT)]
autorelease];
[cell.contentView addSubview:topLabel];
//
// Configure the properties for the text that are the same on every row
//
topLabel.tag = TOP_LABEL_TAG;
topLabel.backgroundColor = [UIColor clearColor];
topLabel.textColor = [UIColor colorWithRed:0.25 green:0.0 blue:0.0 alpha:1.0];
topLabel.highlightedTextColor = [UIColor colorWithRed:1.0 green:1.0 blue:0.9 alpha:1.0];
topLabel.font = [UIFont systemFontOfSize:[UIFont labelFontSize]];
topLabel.textAlignment = UITextAlignmentCenter;
/*
//
// Create the label for the bottom row of text
//
bottomLabel =
[[[UILabel alloc]
initWithFrame:
CGRectMake(
image.size.width + 2.0 * cell.indentationWidth,
0.5 * (aTableView.rowHeight - 2 * LABEL_HEIGHT) + LABEL_HEIGHT,
aTableView.bounds.size.width -
image.size.width - 4.0 * cell.indentationWidth
- indicatorImage.size.width,
LABEL_HEIGHT)]
autorelease];
[cell.contentView addSubview:bottomLabel];
//
// Configure the properties for the text that are the same on every row
//
bottomLabel.tag = BOTTOM_LABEL_TAG;
bottomLabel.backgroundColor = [UIColor clearColor];
bottomLabel.textColor = [UIColor colorWithRed:0.25 green:0.0 blue:0.0 alpha:1.0];
bottomLabel.highlightedTextColor = [UIColor colorWithRed:1.0 green:1.0 blue:0.9 alpha:1.0];
bottomLabel.font = [UIFont systemFontOfSize:[UIFont labelFontSize] - 2];
*/
//
// Create a background image view.
//
cell.backgroundView =
[[[UIImageView alloc] init] autorelease];
cell.selectedBackgroundView =
[[[UIImageView alloc] init] autorelease];
#endif
}
#if USE_CUSTOM_DRAWING
else
{
topLabel = (UILabel *)[cell viewWithTag:TOP_LABEL_TAG];
// bottomLabel = (UILabel *)[cell viewWithTag:BOTTOM_LABEL_TAG];
}
topLabel.text = [arrayList objectAtIndex:indexPath.row];
//bottomLabel.text = [NSString stringWithFormat:#"Some other information.", [indexPath row]];
// [cell LabelText:[arrayList objectAtIndex:indexPath.row]];
//
// Set the background and selected background images for the text.
// Since we will round the corners at the top and bottom of sections, we
// need to conditionally choose the images based on the row index and the
// number of rows in the section.
//
UIImage *rowBackground;
UIImage *selectionBackground;
NSInteger sectionRows = [aTableView numberOfRowsInSection:[indexPath section]];
NSInteger row = [indexPath row];
if (row == 0 && row == sectionRows - 1)
{
rowBackground = [UIImage imageNamed:#"topAndBottomRow.png"];
selectionBackground = [UIImage imageNamed:#"topAndBottomRowSelected_copy.png"];
}
else if (row == 0)
{
rowBackground = [UIImage imageNamed:#"topRow.png"];
selectionBackground = [UIImage imageNamed:#"topRowSelected_copy.png"];
}
else if (row == sectionRows - 1)
{
rowBackground = [UIImage imageNamed:#"bottomRow.png"];
selectionBackground = [UIImage imageNamed:#"bottomRowSelected_copy.png"];
}
else
{
rowBackground = [UIImage imageNamed:#"middleRow.png"];
selectionBackground = [UIImage imageNamed:#"middleRowSelected_copy.png"];
}
((UIImageView *)cell.backgroundView).image = rowBackground;
((UIImageView *)cell.selectedBackgroundView).image = selectionBackground;
if (row == 0)
{
cell.imageView.image = [UIImage imageNamed:#"pic1.png"];
}
else if (row == 1)
{
cell.imageView.image = [UIImage imageNamed:#"pic2.png"];
}
else if (row == 2)
{
cell.imageView.image = [UIImage imageNamed:#"pic3.png"];
}
else if (row == 3)
{
cell.imageView.image = [UIImage imageNamed:#"pic4.png"];
}
else if (row == 4)
{
cell.imageView.image= [UIImage imageNamed:#"pic5.png"];
}
#else
[cell LabelText:[arrayList objectAtIndex:indexPath.row]];
//cell.text = [NSString stringWithFormat:#"Cell at row %ld.", [indexPath row]];
#endif
return cell;
}
The issue you are probably having is accessing object 1 as index 1... Arrays in Objective-C are the same as most other C structured languages. Indexed starting at 0.
Put this code in.
for (int i = 0; i < [arrayList count]; i++)
{
NSLog(#"Item %d = %#", i, [arrayList objectAtIndex:i]);
}
Chances are good that this works fine.
If that is not the case the I would recommend restoring your iphone to factory default as either the operating system is malfunctioning, or you have other rogue processes that are corrupting memory.
To debug the code above. As you are grabbing the items out of the array I would put in an NSLog()
NSString *objectAtIndex = [arrayList objectAtIndex:indexPath.row];
NSLog(#"Row: %d, Object: %#, Count: %d",indexPath.row, objectAtIndex, [arrayList count]);
[cell LabelText:[arrayList objectAtIndex:indexPath.row]];
- (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] autorelease];
}
cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
return cell;
}
Are you doing something similar to this for populating table view
NSMutableArray *ArrayList=[[NSMutableArray alloc]initWithObjects: #"My First String",
#"My Second String",
#"My Third String",
#"My Forth String",
#"My Fifth Sring",
nil];

Iphone cellForRowAtIndexPath Jerky when scrolling asynchronously problem

I've released my app and noticed the jerkyness when scrolling in the CellForRowAtIndexPath, this is because i'm rendering an image from an JSON Feed via a URL. I've searched the internet and found a few examples and this one i've almost got working. The problem is when it renders the images don't match the correct title. Can someone please have a look and see what if i'm doing something obviously wrong.
Anyway here is my code:
- (void)displayImage:(UIImage *)image {
[photo setImage:image];
}
-(void)loadImage:(NSString *)url {
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
CellForRowAtIndexPath Methord
#define DATELABEL_TAG 1 #define MAINLABEL_TAG 2 #define PHOTO_TAG 3 UIImageView *photo;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MainNewsCellIdentifier = #"MainNewsCellIdentifier";
UILabel *mainLabel, *dateLabel;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: MainNewsCellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier: MainNewsCellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
dateLabel = [[[UILabel alloc] initWithFrame:CGRectMake(15.0,15.0,170.0,15.0)] autorelease];
dateLabel.tag = DATELABEL_TAG;
dateLabel.font = [UIFont systemFontOfSize:10.0];
dateLabel.textAlignment = UITextAlignmentLeft;
dateLabel.textColor = [UIColor darkGrayColor];
dateLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
[cell.contentView addSubview:dateLabel];
mainLabel = [[[UILabel alloc] initWithFrame:CGRectMake(15.0,28.0,170.0,60.0)] autorelease];
mainLabel.tag = MAINLABEL_TAG;
mainLabel.font = [UIFont boldSystemFontOfSize:14.0];
mainLabel.textColor = [UIColor blackColor];
mainLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;
mainLabel.numberOfLines = 0;
[cell.contentView addSubview:mainLabel];
photo = [[[UIImageView alloc] initWithFrame:CGRectMake(190.0,15.0,85.0,85.0)] autorelease];
photo.tag = PHOTO_TAG;
photo.contentMode = UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:photo];
}
else {
dateLabel = (UILabel *)[cell.contentView viewWithTag:DATELABEL_TAG];
mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];
photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
}
NSUInteger row = [indexPath row];
NSDictionary *stream = (NSDictionary *) [dataList objectAtIndex:row];
NSString *title = [stream valueForKey:#"title"];
NSString *titleString = #"";
if( ! [title isKindOfClass:[NSString class]] )
{
titleString = #"";
}
else
{
titleString = title;
}
CGSize maximumSize = CGSizeMake(180, 9999);
UIFont *dateFont = [UIFont fontWithName:#"Helvetica" size:14];
CGSize dateStringSize = [titleString sizeWithFont:dateFont
constrainedToSize:maximumSize
lineBreakMode:mainLabel.lineBreakMode];
CGRect dateFrame = CGRectMake(15.0, 28.0, 170.0, dateStringSize.height);
mainLabel.frame = dateFrame;
mainLabel.text = titleString;
dateLabel.text = [stream valueForKey:#"created"];
NSString *i = [NSString stringWithFormat:#"http://www.domain.co.uk/images/stories/%#", [stream valueForKey:#"image"]];
photo.image = [UIImage imageNamed:#"i_digital_media.png"];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage:)
object:i];
[queue addOperation:operation];
[operation release];
return cell;}
By the time that your image is loaded, the photo variable is pointed to a different photo :)
You need to pass both the loaded image and the UIImageView you want to update back - try using a NSDictionary to pass variables between threads :
- (void)displayImage:(NSDictionary *)info {
[[info objectForKey:#"photo"] setImage:[info objectForKey:#"image"]];
}
-(void)loadImage:(NSDictionary *)info {
NSString *imagePath = [info objectForKey:#"imagePath"];
UIImageView *photo = [info objectForKey:#"photo"];
// Load the image
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage* image = [[[UIImage alloc] initWithData:imageData] autorelease];
[imageData release];
// Pass it back to the main thread
NSDictionary *mainThreadInfo = [NSdictionary dictionaryWithObjectAndKeys:image, #"image", photo, #"photo", nil];
[self performSelectorOnMainThread:#selector(displayImage:) withObject:mainThreadInfo waitUntilDone:YES];
}
so now, your operation will pass the photo and the image data back to the main thread. Create the operation like this :
NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:i, #"imagePath", photo, #"photo", nil];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage:)
object:info];
And get rid of the global photo variable :)

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.