Strange UIImageview remote image loading behaviour - iphone

I am trying to load remote image on my imageview using the following code. displayImage is referenced with imageview at testview.xib
- (void)viewDidLoad
{
[super viewDidLoad];
self.displayImage.userInteractionEnabled = YES;
NSMutableURLRequest *requestWithBodyParams = [NSMutableURLRequest requestWithURL:self.gImg.URL];
NSData *imageData = [NSURLConnection sendSynchronousRequest:requestWithBodyParams returningResponse:nil error:nil];
self.originalImage = [UIImage imageWithData:imageData];
self.displayImage.contentMode = UIViewContentModeScaleAspectFit;
self.displayImage = [[UIImageView alloc] initWithImage:self.originalImage];
[self.displayImage setImage:self.originalImage];
NSLog(#"DisplayImage Object:%#",self.displayImage);
NSLog(#"height of Displayimage image:%.f",self.displayImage.image.size.height);
}
But the image is not showing. I am certain image did loaded on imageview. Here is output log:
DisplayImage Object:<UIImageView: 0x11033270; frame = (0 0; 720 632); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1104c620>>
height of Displayimage image:632

Here I am modified your code:
No need to alloc the UIImageView in code, if you have the UIImageView in .xib.
NSURL *gImg = [NSURL URLWithString:#"http://www.vinfotech.com/sites/default/files/iphoe-app-design-ios7-way-12.jpg"];
NSMutableURLRequest *requestWithBodyParams = [NSMutableURLRequest requestWithURL:gImg];
NSData *imageData = [NSURLConnection sendSynchronousRequest:requestWithBodyParams returningResponse:nil error:nil];
UIImage *originalImage = [UIImage imageWithData:imageData];
self.displayImage.contentMode = UIViewContentModeScaleAspectFit;
// self.displayImage = [[UIImageView alloc] initWithImage:originalImage];
[self.displayImage setImage:originalImage];
NSLog(#"DisplayImage Object:%#",self.displayImage);
NSLog(#"height of Displayimage image:%.f",self.displayImage.image.size.height);
Hope so, this code helps you.

Create a dispatch queue:
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mayapp", NULL);
Use NSData method dataWithContentsOfURL and download the image in a background thread:
dispatch_async(backgroundQueue, ^(void) {
NSData *data = [NSData dataWithContentsOfURL:requestWithBodyParams];
//as soon as the image is downloaded, draw image in a main thread
dispatch_sync(dispatch_get_main_queue(), ^(void) {
self.originalImage = [UIImage imageWithData:data];
self.displayImage.contentMode = UIViewContentModeScaleAspectFit;
self.displayImage = [[UIImageView alloc] initWithImage:self.originalImage];
[self.displayImage setImage:self.originalImage];
});//close main block
});//background block

This Sample code works fine for me :
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:#"http://iceclearmedia.com/wp-content/uploads/2011/04/SEO-and-url-Shorteners.jpg"];
NSData* imageData = [[NSData alloc] initWithContentsOfURL:url];
UIImage* image = [[UIImage alloc] initWithData:imageData] ;
[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
- (void)displayImage:(UIImage *)image {
[self.imagedownload setImage:image]; //UIImageView
}

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: Memory used by images is not freed

I have this code below that loads images from the web.
Those images are shown after clicking on a table cell, and they are reloaded every time the table cell is clicked.
The point is that analyzing the memory allocation with "Instruments", when I go back from the detail view to the table, the memory occupied from the images is not freed.
Does anyone have any suggestion?
I, of course, do all the release of the case... but it seems to don't help.
NSError *error = nil;
UIImage *img = nil;
NSString *myurl = [IMG_SERVER_URL stringByAppendingString: tmp_link.url];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSData *imageData = nil;
if(myurl!=nil){
imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:myurl] options:nil error:&error];
if (error == 0) {
img = [[UIImage alloc] initWithData:imageData];
}
}
[imageData release]; imageData = nil;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(targetWidth*i, 0, targetWidth, targetHeight)];
imageView.image = img;
imageView.contentMode = UIViewContentModeScaleAspectFit;
[img release];
[....some code....]
[imageView release];
I think "imageView.image = img" increases the reference count on the image object. If I'm right the allocated memory will not get freed as long as you don't release the imageView.

Calling a Method in viewDidLoad()

I have a little Problem, i have implemented the following method to
open an Image:
- (void)ladeImage {
id path = #"http://172.23.1.63:8080/RestfulJava/pics";
NSURL *url = [NSURL URLWithString:path];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
[self.view addSubview:imgView];
}
But how i can implement this method in the viewDidLoad() Method of this class.
Could someone help me, please?
If this is within your implementation of a UIViewController subclass, then just copy & paste the code from within your ladeImage method into viewDidLoad (xcode will prepare method implementations for you and comment them out if you start a VC subclass, you need to uncomment it).
It should look like this:
-(void)viewDidLoad {
[super viewDidLoad];
id path = #"http://172.23.1.63:8080/RestfulJava/pics";
NSURL *url = [NSURL URLWithString:path];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
[self.view addSubview:imgView];
}
of course you could leave things as they are and just call [self ladeImage]; in your implementation of viewDidLoad.

Xcode iPhone Programming: Loading a jpg into a UIImageView from URL

My app has to load an image from a http server and displaying it into an UIImageView
How can i do that??
I tried this:
NSString *temp = [NSString alloc];
[temp stringwithString:#"http://192.168.1.2x0/pic/LC.jpg"]
temp=[(NSString *)CFURLCreateStringByAddingPercentEscapes(
nil,
(CFStringRef)temp,
NULL,
NULL,
kCFStringEncodingUTF8)
autorelease];
NSData *dato = [NSData alloc];
dato=[NSData dataWithContentsOfURL:[NSURL URLWithString:temp]];
pic = [pic initWithImage:[UIImage imageWithData:dato]];
This code is in viewdidload of the view but nothing is displayed!
The server is working because i can load xml files from it. but i can't display that image!
I need to load the image programmatically because it has to change depending on the parameter passed!
Thank you in advance.
Antonio
It should be:
NSURL * imageURL = [NSURL URLWithString:#"http://192.168.1.2x0/pic/LC.jpg"];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];
Once you have the image variable, you can throw it into a UIImageView via it's image property, ie:
myImageView.image = image;
//OR
[myImageView setImage:image];
If you need to escape special characters in your original string, you can do:
NSString * urlString = [#"http://192.168.1.2x0/pic/LC.jpg" stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSURL * imageURL = [NSURL URLWithString:urlString];
....
If you're creating your UIImageView programmatically, you do:
UIImageView * myImageView = [[UIImageView alloc] initWithImage:image];
[someOtherView addSubview:myImageView];
[myImageView release];
And because loading image from URL takes ages, it would be better to load it asynchronously. The following guide made it stupid-simple for me:
http://www.switchonthecode.com/tutorials/loading-images-asynchronously-on-iphone-using-nsinvocationoperation
Try this
NSURL *url = [NSURL URLWithString:#"http://192.168.1.2x0/pic/LC.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImageView *subview = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f,320.0f, 460.0f)];
[subview setImage:[UIImage imageWithData:data]];
[cell addSubview:subview];
[subview release];
All the Best.
This is the actual code.
UIImageView *myview=[[UIImageView alloc]init];
myview.frame = CGRectMake(0, 0, 320, 480);
NSURL *imgURL=[[NSURL alloc]initWithString:#"http://soccerlens.com/files/2011/03/chelsea-1112-home.png"];
NSData *imgdata=[[NSData alloc]initWithContentsOfURL:imgURL];
UIImage *image=[[UIImage alloc]initWithData:imgdata];
myview.image=image;
[self.view addSubview:myview];
You should load the image in the background or the view will freeze.
Try this:
UIImage *img = [[UIImage alloc] init];
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSData * data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:#"http://www.test.com/test.png"];
img = [UIImage imageWithData: data];
dispatch_async(dispatch_get_main_queue(), ^{
//PUT THE img INTO THE UIImageView (imgView for example)
imgView.image = img;
});
});

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