UIImage not working properly? - iphone

i m trying load UIImages from server asynchronously in UITableViewCell.
My code worked fine in simulator but not on device. My code as follows,
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
IScopeCustomTableCell *cell = (IScopeCustomTableCell *)[tableView dequeueReusableCellWithIdentifier:CellClassName];
if (!cell){
NSArray *topLevelItems = [cellLoader instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
}
cell.delegate = self;
cell.videoTitle.text = [[videoDataArray objectAtIndex:indexPath.row] objectForKey:#"VideoTitle"];
cell.videoLink = [[videoDataArray objectAtIndex:indexPath.row] objectForKey:#"VideoLink"];
cell.videoThumbnailImageLink = [[videoDataArray objectAtIndex:indexPath.row] objectForKey:#"VideoThumbnail"];
cell.videoThumbnail.tag = indexPath.row;
cell.tag = indexPath.row;
[cell.activityIndicator startAnimating];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage:)
object:cell];
[queue addOperation:operation];
return cell;
}
- (void)loadImage:(IScopeCustomTableCell *)cell {
NSLog(#"Image link :- %#", cell.videoThumbnailImageLink);
//NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:cell.videoThumbnailImageLink]];
NSData* imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:cell.videoThumbnailImageLink]];
UIImage* image = [UIImage imageWithData:imageData];
cell.videoThumbnail.image = image;
[cell.activityIndicator stopAnimating];
[cell.activityIndicator removeFromSuperview];
//[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
The above code fine on simulator but not on device, becoz, UIImage *image get (0X0)null in even though NSData loadImage method containing appropriate data.

What you are doing is not the best way to do it as it will create many autoreleased objects and will increase the size of your app and also you are not releasing your operation... so first of all release your operation after [queue addOperation:operation];
and use this code instead for getting the image data and storing it in your image...
NSData* data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:cell.videoThumbnailImageLink]]];
UIImage* img = [[UIImage alloc] initWithData:data];
[data release];
cell.videoThumbnail.image = image;
[img release];
hoping this sorts your problem..

This link containing image cache code and it worked properly exact that i would like.
https://github.com/jakemarsh/JMImageCache

Related

Loading images in background to optimize the loading in ios

I am trying to optimize the load in my application, in fact, I have a lot of images that loaded in my application, and I spend a lot of time waiting for a view controller to open, especially the first initial view which includes a lot of images.
I took a look at apple sample
but I cannot re-work the whole application, what I want is just to tell me specifically what should I do?, I implement?
in the tableview, where the cell is implemented cellforrowatindexpath:
NSURL *imageURL = ......;
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad;
imageLoad = [[UIImage alloc] initWithData:imageData];
imageView.image = imageLoad;
could I do something?
thank you for your help!
Try this code:
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(q, ^{
/* Fetch the image from the server... */
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
/* This is the main thread again, where we set the tableView's image to
be what we just fetched. */
cell.imgview.image = img;
});
});
Yes, you can add placeholder image to it.
It will not slow down the scrolling and will load image accordingly with time.
Also import this file UIImageView+WebCache.m and MapKit Framework
Here is the link to download the files.
- (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];
}
UIImageview* iV = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 50, 50)];
[iV setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage imageNamed:#"image_placeholder.gif"]];
[cell.contentView addSubview:iV];
[iV release];
}
Just clean, build and run.
To enable the app while getting the images from server and disable block while loading the images try to use UIImageView+AFNetworking library to load the image from server asynchronously AFNetworking
NSString *imageUrl = [[dict objectForKey:#"photo"] objectForKey:#"url"];
UIImageView *myImage = [[UIImageView alloc] init];
[myImage setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:#"PlaceHolder.png"]];
Just add this library and include the UIImageView+AFNetworking so you can use the new UIImageView Category imageWithUrl
Take a look at this control:
https://github.com/nicklockwood/AsyncImageView
It's very easy to implement (only 1 header file) and will suit your needs just fine.
Using this control:
Instead of declaring:
NSURL *imageURL = ......;
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad;
imageLoad = [[UIImage alloc] initWithData:imageData];
imageView.image = imageLoad;
Use:
NSURL *imageURL = ......;
imageView.imageURL = imageURL;
you can check this tutorial on NSOperationQueue and this on GCD doing exactly same. Also you can try using:
// Block variable to be assigned in block.
__block NSData *imageData;
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.razeware.imagegrabber.bgqueue", NULL);
// Dispatch a background thread for download
dispatch_async(backgroundQueue, ^(void) {
imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad;
imageLoad = [[UIImage alloc] initWithData:imageData];
// Update UI on main thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
imageView.image = imageLoad;
});
});
You can try something like this!....
dispatch_queue_t checkInQueueForPostImage = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(checkInQueueForPostImage, ^{
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:postAndCheckInDetails.postImageURL]]];
dispatch_sync(dispatch_get_main_queue(), ^{
if (image!=nil) {
[uploadImage setImage:image];
}
[cell setNeedsLayout];
});
});
Here is a slightly modified approach of Ramu Pasupoletis answer. I added the
__block
modifier to make the var img visible inside the block called on the main thread. Here is the complete method definition which I use in
-(UITableViewCell*)cellforRowAtIndexPath:(UIIndexPath*)indexPath;
for fetching the thumbnails lazily. I also added placeholders there for the cells UIImageViews.
//lazy loading of thumbnails for images in cell via bg thread
-(void)loadImageForCell:(CustomEditTableViewCell*)theCell withFilepath: (NSString*)filepath{
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(q, ^{
UIImage (__block *img) = [UIImage imageWithContentsOfFile:filepath];
UIImage *thumbnail = [[GlobalFunctions sharedGlobalFunctions] imageOfSize:CGSizeMake(40, 40) fromImage:img];
dispatch_async(dispatch_get_main_queue(), ^{
theCell.imageView.image = thumbnail;
});
});
}
Use IDAsyncImageView.h
//////////////////////////////////////
IDAsyncImageView.h
/////////////////////////////////////
#interface IDAsyncImageView : NSObject
#property (nonatomic, strong) NSCache *cache;
+ (instancetype)instance;
- (void)loadImageView:(UIImageView*)imageView withURLString:(NSString *)urlString;
#end
//////////////////////////////////////
IDAsyncImageView.m
/////////////////////////////////////
#import "IDAsyncImageView.h"
#implementation IDAsyncImageView
+ (instancetype)instance
{
static IDAsyncImageView *_instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
- (instancetype)init
{
self = [super init];
if (self) {
self.cache = [[NSCache alloc] init];
}
return self;
}
- (void)loadImageView:(UIImageView*)imageView withURLString:(NSString *)urlString
{
UIActivityIndicatorView* activityView;
activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityView.hidesWhenStopped = YES;
activityView.center = CGPointMake(imageView.bounds.size.width / 2.0f, imageView.bounds.size.height / 2.0f);
activityView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
[imageView addSubview:activityView];
[activityView startAnimating];
UIImage* imageLoad = [self.cache objectForKey:urlString];
if (nil != imageLoad) {
imageView.image = imageLoad;
[activityView removeFromSuperview];
}
else {
// Block variable to be assigned in block.
__block NSData *imageData;
// Dispatch a background thread for download
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
UIImage* imageLoad = [[UIImage alloc] initWithData:imageData];
// Update UI on main thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self.cache setObject:imageLoad forKey:urlString];
imageView.image = imageLoad;
[activityView removeFromSuperview];
});
});
}
}
//////////////////////////////////////
ViewController.m
//////////////////////////////////////
- (void)viewDidLoad {
[super viewDidLoad];
[[IDAsyncImageView instance] loadImageView:myImageView withURLString:aUrl];
}
You can use async imageview.
- (void) loadImageFromURL:(NSURL*)url placeholderImage:(UIImage*)placeholder cachingKey:(NSString*)key {
self.imageURL = url;
self.image = placeholder;
NSData *cachedData = [FTWCache objectForKey:key];
if (cachedData) {
self.imageURL = nil;
self.image = [UIImage imageWithData:cachedData];
return;
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *imageFromData = [UIImage imageWithData:data];
[FTWCache setObject:data forKey:key];
if (imageFromData) {
if ([self.imageURL.absoluteString isEqualToString:url.absoluteString]) {
dispatch_sync(dispatch_get_main_queue(), ^{
self.image = imageFromData;
});
} else {
// NSLog(#"urls are not the same, bailing out!");
}
}
self.imageURL = nil;
});
}
Take a look at this link.You will have an idea on using async imageview.

Iphone loading an URL to a variable - static works, dynamic from XML falls over

I load my XML in to my iphone app via:
NSArray *Images = [doc nodesForXPath:kName_logo error:nil];//Root node
for (CXMLElement *ImgIcons in Images)
{
NSArray *locImage = [ImgIcons elementsForName:kName_image];
for(CXMLElement *fullImage in locImage)
{
LocationImage = fullImage.stringValue;
locStatImage = LocationImage;
NSLog(#"Image Found %#",LocationImage);
break;
}
}
Which is fine, it's bringing me back the correct string
2011-11-03 14:48:43.572 Del Search[13152:f203] Image Found http://de1128/directenquirieswebapplicationv3.0/images/logos/PremierInn.jpg
However, When I load it on to my table through the following:
if (indexPath.section == 0)
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierImage];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifierImage] autorelease];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,320,180)];
imageView.tag = 1;
NSURL *Imageurl = [NSURL URLWithString:[NSString stringWithFormat:#"%#", locStatImage]];
NSData *data = [NSData dataWithContentsOfURL:Imageurl];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];
imageView.image = img;
[cell addSubview:imageView];
[imageView release];
}
return cell;
}
The app falls over. However if I manually set locStatImage by doing:
locStatImage = #"http://de1128/directenquirieswebapplicationv3.0/images/logos/PremierInn.jpg";
It works fine. What' am I doing wrong when I set locStatImage?
Thanks
Tom
Assuming the two code snippets above are from separate methods, locStatImage is probably being autoreleased between you obtaining it from the XML and using it in your cellForRowAtIndexPath method.
Further assuming locStatImage is a retained property (if it isn't it should be), in your first code sample you should use
self.locStatImage = ...

Load image to a tableView from URL iphone sdk

I have tableView and need to load image from URL. I have an array that contains the URLs of images and when the page loads I need to load all the images into the tableview. Note that, not from a single URL, have an array with different URLs. How can I implement that? Please help
Thanks.
You can use GCD to load images in background thread, like this:
//get a dispatch queue
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//this will start the image loading in bg
dispatch_async(concurrentQueue, ^{
NSData *image = [[NSData alloc] initWithContentsOfURL:imageURL];
//this will set the image when loading is finished
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:image];
});
});
Hi. But you probably need to add a dispatch_release(concurrentQueue); to be sure no leak. – Franck Aug 25 at 19:43
You can use Lazy Loading when you want to download Images from internet
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//All you reusable cell implementation here.
//Since your Images sizes differ. Keep a custom Imageview
if(![imagesForCategories containsObject:indexPath])
{
customImageView.image = [UIImage imageNamed:#"default-image.png"];
NSMutableArray *arr = [[NSArray alloc] initWithObjects:[imageUrlArray objectAtIndex:indexPath.row],indexPath, nil];
[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:arr];
[arr release];
}
return cell;
}
- (void) loadImageInBackground:(NSArray *)urlAndTagReference
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *imgUrl=[[NSURL alloc] initWithString:[urlAndTagReference objectAtIndex:0]];
NSData *imgData = [NSData dataWithContentsOfURL:imgUrl];
UIImage *img = [UIImage imageWithData:imgData];
[imgUrl release];
NSMutableArray *arr = [[NSMutableArray alloc ] initWithObjects:img,[urlAndTagReference objectAtIndex:1], nil ];
[self performSelectorOnMainThread:#selector(assignImageToImageView:) withObject:arr waitUntilDone:YES];
[arr release];
[pool release];
}
- (void) assignImageToImageView:(NSMutableArray *)imgAndTagReference
{
[imagesForCategories addObject:[imgAndTagReference objectAtIndex:1]];
UITableViewCell *cell = [celebCategoryTableView cellForRowAtIndexPath:[imgAndTagReference objectAtIndex:1]];
UIImageView *profilePic = (UIImageView *)[cell.contentView viewWithTag:20];
profilePic.image = [imgAndTagReference objectAtIndex:0];
}
You can use SDWebImage which permits very easy and speed loading of images in UITableView.
https://github.com/rs/SDWebImage
Try this code,imagearray contains urls of image
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString: [imagearray objectAtIndex:row]]];
UIImage* image = [[UIImage alloc] initWithData:imageData];
cell.imageView.image =image;
return cell;
}
You need to create your custom cell for lazy loading. This will allow you to download images correctly and without freezing. Here is nice example how to do this:
Asynch image loading
With afnetworki, it is too easy.
//afnetworking
#import "UIImageView+AFNetworking.h"
[cell.iboImageView setImageWithURL:[NSURL URLWithString:server.imagen] placeholderImage:[UIImage imageNamed:#"qhacer_logo.png"]];

Help me on loading the images on table view using NSOperationQueue

Kindly look the below code..i found from web
- (void) loadData {
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(loadDataWithOperation) object:nil];
[queue addOperation:operation];
[operation release];
}
- (void) loadDataWithOperation {
NSURL *dataURL = [NSURL URLWithString:#"http://icodeblog.com/samples/nsoperation/data.plist"];
NSArray *tmp_array = [NSArray arrayWithContentsOfURL:dataURL];
for(NSString *str in tmp_array) {
[self.array addObject:str];
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[cell.textLabel setText:[self.array objectAtIndex:indexPath.row]];
return cell;
}
I have found the above code which loads the text from the web without any problem.( i mean gui is not hanging ).like wise i want to load images into the table view.for that i have wriiten the below code.
- (void) loadDataWithOperation {
NSString *Img_id, *Img_name, *DynamicImgUrl;
Img_id = xmltag.equip_id;
Img_name = xmltag.image;
DynamicImgUrl = [NSString stringWithFormat:#"http://test.com/pics/equipment/%#/%#",Img_id, Img_name];
NSURL *ImageUrl = [NSURL URLWithString:DynamicImgUrl];
//UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:ImageUrl]];
NSArray *tmp_array = [NSArray arrayWithContentsOfURL:ImageUrl];
for(NSString *str in tmp_array) {
[self.array addObject:str];
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}
Am i correct here? how can i go with adding into the table view...
Kindly help me out...
U are seeking to display images on Tableview from URL, when u download image from url we need to consider some issues, it will freeze ur table view if u goahead with ordinary loading image.
i suggest u look at LazyLoading image
u see this link http://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html
Download this sample and get to know the things

setting the images in a tableview which i am getting from the server?

I am using the code below to set images in a table which are loaded from the server, but I have an exception thrown (not every time) which is related to a drawing error
- (void) getTheThumnbails:(NSIndexPath *)indexPath{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
GDataEntryYouTubeVideo *entry = [feedArray objectAtIndex:indexPath.row];
NSURL *url = [[NSURL alloc] initWithString:[[[[entry mediaGroup] mediaThumbnails] objectAtIndex:0] URLString]];
NSData *imgData = [[NSData alloc] initWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:imgData];
CGRect newFrame = CGRectMake(0.0, 0.0, 62.0, 62.0);
UIGraphicsBeginImageContext(newFrame.size);
[img drawInRect:newFrame];
UIImage *resizedImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[imgDict setObject:resizedImg forKey:[NSString stringWithFormat:#"%i",indexPath.row]];
[[[myTableView cellForRowAtIndexPath:indexPath] imageView] setImage:resizedImg];
[pool release];
}
Please help me folks, sorting out the mistake i am doing.
Trying to draw a image in a thread is not a good practice, please do not perform any UI operations in thread, they need to be done in the main thread.
well I did the above like
- (void) getTheThumnbails:(NSIndexPath *)indexPath{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
GDataEntryYouTubeVideo *entry = [feedArray objectAtIndex:indexPath.row];
NSURL *url = [[NSURL alloc] initWithString:[[[[entry mediaGroup] mediaThumbnails] objectAtIndex:0] URLString]];
NSData *imgData = [[NSData alloc] initWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:imgData];
[imgDict setObject:img forKey:[NSString stringWithFormat:#"%i",indexPath.row]];
[img release];
[self performSelectorOnMainThread:#selector(setImageInTable:) withObject:indexPath waitUntilDone:NO];
[pool release];
}
- (void)setImageInTable:(NSIndexPath *)indexPath{
UIImage *img = (UIImage *)[imgDict valueForKey:[NSString stringWithFormat:#"%i",indexPath.row]];
CGRect newFrame = CGRectMake(0.0, 0.0, 62.0, 62.0);
UIGraphicsBeginImageContext(newFrame.size);
[img drawInRect:newFrame];
UIImage *resizedImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[imgDict removeObjectForKey:[NSString stringWithFormat:#"%i",indexPath.row]];
[imgDict setObject:resizedImg forKey:[NSString stringWithFormat:#"%i",indexPath.row]];
[[[myTableView cellForRowAtIndexPath:indexPath] imageView] setImage:resizedImg];
}
Hope this helps.
Thanks,
Madhup