iPhone image memory leak - iphone

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.

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

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

AsyncImage get picture from program source?

from this code
#import "AsyncImageView.h"
#import "ImageCache.h"
#import "ImageCacheObject.h"
static ImageCache *imageCache = nil;
#implementation AsyncImageView
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
}
- (void)dealloc {
[connection cancel];
[connection release];
[data release];
[super dealloc];
}
-(void)loadImageFromURL:(NSURL*)url {
if (connection != nil) {
[connection cancel];
[connection release];
connection = nil;
}
if (data != nil) {
[data release];
data = nil;
}
if (imageCache == nil)
imageCache = [[ImageCache alloc] initWithMaxSize:2*1024*1024];
[urlString release];
urlString = [[url absoluteString] copy];
UIImage *cachedImage = [imageCache imageForKey:urlString];
if (cachedImage != nil)
{ NSLog(#"get in");
if ([[self subviews] count] > 0)
{
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImageView *imageView = [[[UIImageView alloc] initWithImage:cachedImage] autorelease];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout];
[self setNeedsLayout];
return;
}
#define SPINNY_TAG 5555
UIActivityIndicatorView *spinny = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinny.tag = SPINNY_TAG;
spinny.center = self.center;
[spinny startAnimating];
[self addSubview:spinny];
[spinny release];
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)incrementalData {
if (data==nil) {
data = [[NSMutableData alloc] initWithCapacity:2048];
}
[data appendData:incrementalData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)aConnection {
[connection release];
connection = nil;
UIView *spinny = [self viewWithTag:SPINNY_TAG];
[spinny removeFromSuperview];
if ([[self subviews] count] > 0) {
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImage *image = [UIImage imageWithData:data];
[imageCache insertImage:image withSize:[data length] forKey:urlString];
UIImageView *imageView = [[[UIImageView alloc]
initWithImage:image] autorelease];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout]; // is this necessary if superview gets setNeedsLayout?
[self setNeedsLayout];
[data release];
data = nil;
}
#end
If I wanna get picture from app source if url is empty , what code should I add ??
and here is more code from xyz.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.newsTable dequeueReusableCellWithIdentifier:
CellIdentifier];
if (cell == nil) {
//cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell = [self getCellContentView:CellIdentifier];
}
else{
AsyncImageView *oldImage = (AsyncImageView *)[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}
int index = [indexPath indexAtPosition: [indexPath length] - 1];
//Get Picture
CGRect frame;
frame.size.width=50; frame.size.height=50;
frame.origin.x=10; frame.origin.y=0;
AsyncImageView* asyncImage = [[[AsyncImageView alloc] initWithFrame:frame] autorelease];
asyncImage.tag = 999;
NSString *string = [jsonPic objectAtIndex:index];
NSString *url=[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSURL *imageURL = [NSURL URLWithString:url];
if([string isEqualToString:#""]){
NSLog(#"Not found");
at here I don't know How can I get picture from source
AsyncImageView * NoImage = [[[AsyncImageView alloc] initWithFrame:frame] autorelease];
NoImage.tag = 999;
NoImage.image = [UIImage imageNamed:#"bl-noImg.gif"];
[cell.contentView addSubview:NoImage];
}
else
{ NSLog(#"image URL %#",imageURL);
[asyncImage loadImageFromURL:imageURL];
[cell.contentView addSubview:asyncImage];
I can get picture from asyncImage
Please , Help me or guide me to do that. thank you
.
.
.
.
Now It's all done and here is my result code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.newsTable dequeueReusableCellWithIdentifier:
CellIdentifier];
if (cell == nil) {
//cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell = [self getCellContentView:CellIdentifier];
}
else{
AsyncImageView *oldImage = (AsyncImageView *)[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}
int index = [indexPath indexAtPosition: [indexPath length] - 1];
//Get Picture
CGRect frame;
frame.size.width=50; frame.size.height=50;
frame.origin.x=10; frame.origin.y=0;
AsyncImageView* asyncImage = [[[AsyncImageView alloc] initWithFrame:frame] autorelease];
asyncImage.tag = 999;
NSString *string = [jsonPic objectAtIndex:index];
if([string isEqualToString:#""]){
//NSLog(#"Not found");
UIImageView * NoImg = [[[UIImageView alloc] initWithFrame:frame] autorelease];
NoImg.tag = 999;
[NoImg setImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"bg-noImg" ofType:#"gif"]]];
[cell.contentView addSubview:NoImg];
}
else
{ //NSLog(#"image URL %#",imageURL);
NSString *url=[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSURL *imageURL = [NSURL URLWithString:url];
[asyncImage loadImageFromURL:imageURL];
[cell.contentView addSubview:asyncImage];
}
thank you everyone : )
If you are checking for empty url then you should check it before calling to loadImageFromURL and even before creating NSURL object. If it is not empty then you should create NSURL object and call loadImageFromURL method.
somewhere in your code... from where you are calling loadImageFromURL:
if(urlString !=nil || [urlString length]>0)
{
create NSURL object
now again check NSURL object whether its nil or not
we are checking it because if the urlString has incorrect url pattern then no
NSURLObject would be created, so if there is no NSURLObject then we should not call
your method.
if(NSURLObject !=nil)
{
call loadImageFromURL method and so on
}
else
{
//load some default image. which will convey no URL Found
}
}
else
{
//load some default image. which will convey no URL Found
}
Thanks,

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