I am creating a custom UITableViewCell to include an UIImageView and some related text. I am getting the images from the Internet and while the images load, I display a temporary UIImage.
I am using a separate thread to get the UIImage. Once an UIImage is downloaded, I am firing a method on the main thread to set the image in the UIImageView (getting the instance of UIImageView using tags)
But whatever I do, the images are not changed. The cells still display older images (corresponding to different row - due to reusing of cells) and new images are not reflected. Log statements show that the method to set the image is being called.
I even tried changing the image to a static image in willDisplayCell:forRowAtIndexPath:
but even then the image does not change.
Edit
I tried calling reloadData on the UITableView after changing the UIImage, but the UIImage still does not change.
Here's the relevant piece of code
cellForRowAtIndexPath
image = [imagesArray valueForKey:[NSString stringWithFormat:#"%i",indexPath.row]];
if(image == nil){
//display temporary images. When scrolling stops, detach new thread to get images for rows visible
NSString *pth = [[NSBundle mainBundle] pathForResource:#"folder" ofType:#"png"];
image = [UIImage imageWithContentsOfFile:pth];
[imgView setImage:image];
}
else{
[imgView setImage:image];
}
Method which is called on the main thread after an image is downloaded
-(void)setImageInArray:(NSIndexPath *)indPath{
[filesTable reloadData];
}
In the thread, I am adding the UIImage object to imagesArray. So when the next time the cellForRowAtIndex method is called on reloadData, the new UIImage should be displayed.
UITableView's cells are cached, so modifying the cell after it has been rendered will have no effect. Try sending the table a reloadData message, after updating the UIImageView.
Related
I have a UIView holding many things including a UITableView at the bottom. I need to print this page and have all rows show in the final product but I run into problems with rows that are not currently visible in the TableView.
My current attempt to get a final product is to convert my view to a PDF and I have ready Apple's Drawing and Printing guide but it does not give me all the steps I need.
How can I print a UIView and have all the TableView rows, within the UIView, show in the print?
Try the contentSize method, which is inherited from UITableView’s superclass, UIScrollView. However, you may find that contentSize returns an incorrect or out of date value, so you should probably call layoutIfNeeded first to recalculate the table’s layout.
[tableView layoutIfNeeded];
// Allows you to perform layout before the drawing cycle happens.
//-layoutIfNeeded forces layout early. So it will correctly return the size. Like dreaming before doing.
CGSize newTableSize=tableView.contentSize;
- (NSMutableData*)generatePDF {
NSMutableData * pdfData=[NSMutableData data];
[[NSBundle mainBundle] loadNibNamed:#"PDFView" owner:self options:nil];
UIGraphicsBeginPDFContextToData(pdfData, CGRectZero,nil);
CGContextRef pdfContext=UIGraphicsGetCurrentContext();
UIGraphicsBeginPDFPage();
// update the UI elements (IBOutlet on xib file)
//PDFView is main view on xib file containing uitableview too
[self.PDFView.layer renderInContext:pdfContext];
// end PDF context.
UIGraphicsEndPDFContext();
return pdfData;
}
I have an asychronous image loader which loads images (JImage) in a UIImageview. I want to display these in a tablecell. Obviously i cant set cell.imageView.image because i dont have an image, i just have a view.
How do i set the UIImageview to the tablecell? cell.backgroundView works though, but that paints over the whole cell.
The JImage code is:
NSURL *theUrl=[NSURL URLWithString:imageURL];
JImage *photoImage=[[JImage alloc] init];
[photoImage initWithImageAtURL:theUrl];
[photoImage setContentMode:UIViewContentModeRedraw];
[photoImage setFrame:CGRectMake(0.0f, 0.0f, 40.0f, 65.0f)];
cell.backgroundView = photoImage;
[photoImage release];
which in the JImage.m:
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection
{
[self setImage:[UIImage imageWithData: data]];
}
use this code and set frame according to your need.
UIImage *imagearrow = [UIImage imageNamed:#"arrow.png"];
UIImageView *imgarrow=[[UIImageView alloc] initWithFrame:CGRectMake(290, 25, 7, 15)];
imgarrow.image =imagearrow;
[cell addSubview:imgarrow];
[imagearrow release];
You don't need to use JImage if all you want to do is load the image asynchronously. One easy way to do this is with GCD and blocks, like so: https://github.com/ChrisTec/iPhone-Book-CodeSamples/blob/master/Chapter%2013/RealEstateViewer%2013.2.5/RealEstateViewer/ImageTableViewController.m
Here's a sample chapter of the book Objective-C Fundamentals which I've co-authored that explains this code in depth: http://www.manning.com/fairbairn/OCF_sample_ch13.pdf
To sum it up: When the cell is requested, you look if you already have downloaded the image. If you have, you display it. If not, you display a spinner and start an async GCD block that will fetch the image. One that block is done, it will run another block on the main thread that switches the spinner out for the image. That's all.
I think you should take a different approach to this. Instead of putting your JImage in the cell, hold it somewhere else in the view controller, an NSArray is usually convenient. Then populate the cells with either placeholder images or just leave them empty.
So let's say you have an array with all the JImages that are loading, when the JImage in the position x of the array finishes loading, you reload that specific cell as it follows:
NSIndexPath indexPath = [NSIndexPath indexPathForRow:x inSection:0];
[self.tableView reloadRowsAtIndexPaths:x withRowAnimation:NO];
And in your cellForRow:AtIndexPath you just have to take the image from the JImage object held in the array.
I hope this helps you
Why should we avoid loading a image from server while drawing a cell?
In my app I get data from server which contains image URLs as well. Now, I draw my cells and use these image URLs to fetch image from the server and draw it. Now, sometimes image does not get displayed even if image is actually present at that URL as I can see it through browser.
Is there any cell drawing limitation which could cause this issue? Shall I fetch images when I get data from server.
Does cell rendering happens before image is actually drawn.
NSString *imgUrl = [ImageURLArray objectAtIndex:indexPath.row];
if(imgUrl != nil)
{
NSString * ImagePath;
NetworkManager *manager = [[NetworkManager alloc] init];
ImagePath = [manager GetFile:imgUrl];
[manager release];
manager = nil;
if(ImagePath != nil)
{
UIImage *newImage = [UIImage imageWithData:[NSData dataWithContentsOfFile:ImagePath]];
UIGraphicsBeginImageContext(CGSizeMake(50, 50));
// now redraw our image in a smaller rectangle.
[newImage drawInRect:CGRectMake(25, 10, 30, 30)];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
cell.imageView.image = newImage;
}
}
return cell;
}
hope this will solve your problem
What could be happening is you have a main thread which is the UI display thread. By fetching image from a url from this thread, you are essentially blocking the cell (i.e. scrolling). Also might be the case that the image is in the process of downloading in which case you'll not see it till it downloads.
Generally UITableView does not display the cell till it's ready to be displayed, by doing the image download in the main thread you are harming your performance. What you should do is to launch a background thread which downloads the image from the url & then update the cell of the image contents when the download is ready.
Best way is to have an initial placeholder like a default image or a spinner, which gets replaced when the main image download gets done.
Dont worry you dont need to implement all this. No point in reinventing the wheel. Here's an awesome library which I use for the same - UIImageView + WebCache
fetch images when I you data from server and pass the information to the view.
like
ImageView *imageView = [[ImageView alloc] initWithNibName:#"ImageView" bundle:[NSBundle mainBundle]];
imageView.prod=self.prod;
imageView.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:imageView animated:YES];
[imageView release];
imageView=nil;
hope this will solve your problem
Clearly, the image download is taking more time. You should be using placeholder images until the download completes. You can't stop the user from scrolling.
I have a UIImageView that I have already set an image to. This works fine, but later, I want to change that image. So, I set a new image for the image property, but when I view the app, that image is set as a second image over the first:
UIImageView *image;
image = (UIImageView *)[cell viewWithTag:0];
image.image = [UIImage imageNamed:#"History_Row2.png"];
How can I replace the current image in my UIImageView rather than seeming to add another?!
I did it by retaining the UIImageView, and keeping a reference as an ivar, releasing on dealloc.
image = (UIImageView *)[cell viewWithTag:0];
That was returning a UITableViewCell rather than a UIImageView, this is because the tag 0 is the default and it needs to be changed to a different number. After doing this it worked.
Im trying to load a single image into the grouped table cell. I found a piece of code on the internet and modified it. Original code is using UIViews to display image, which is not what I need, however original code works of course. PLease help me to make this code work to display an image in a sigle cell for grouped tableview. My TableView has only one row and it has UITableViewCellStyleDefault style.
Original Code
Here is my modified method, this is the core method.
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection
{
[connection release];
connection=nil;
UIImage *img = [UIImage imageWithData:data];
self.image = img;
self.frame = self.bounds;
[self setNeedsLayout];
[data release];
data=nil;
}
This is how I use it to display image in my TableView Cell cellForRowAtIndexPath method.
CGRect frame;
frame.size.width=75; frame.size.height=75;
frame.origin.x=0; frame.origin.y=0;
AsyncImageView* asyncImage = [[[AsyncImageView alloc] initWithFrame:frame] autorelease];
[asyncImage loadImageFromURL:imageURL];
cell.imageView.image = asyncImage.image;
In that code you posted, the image of the AsyncImageView doesn't get set until after the connection finishes loading and it actually creates the image. Problem is, you're setting it's image into the cell immediately. That's not going to work!
You're going to want to make a custom cell class (subclass UITableViewCell) and use that cell in your table. There's lots of sample code showing how to use custom cells and lay them out with views. Instead of using UITableViewCell's standard imageView, create your own layout and use an AsyncImageView to show your image. Then it should work.