Downloading image from a url into a UIImageVIew dynamically - ios

I am trying to insert and image into a UIImageView from a url. I used the following code to do so.
When running the program gets stuck at
NSURL *url = [NSURL URLWithString:urlstring];
In the below code and it shows "Thread 1 : signal SIGABRT" on that particular line.
Can someone help me with this and tell if the format that i used is correct or what i had did wrong??
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"newoffer";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *temp = [product objectAtIndex:indexPath.row];
UILabel *Label = (UILabel *)[cell viewWithTag:201];
Label.text = [temp objectForKey:#"item_name"];
UIImageView *Image = (UIImageView *)[cell viewWithTag:200];
NSString *urlstring=[temp objectForKey:#"image_url"];
NSURL *url = [NSURL URLWithString:urlstring];
NSData *data = [NSData dataWithContentsOfURL:url];
Image.image = [UIImage imageWithData:data];
return cell;
}

Change this code:
NSURL *url = [NSURL URLWithString:urlstring];
NSData *data = [NSData dataWithContentsOfURL:url];
Image.image = [UIImage imageWithData:data];
To:
dispatch_queue_t myqueue = dispatch_queue_create("myqueue", NULL);
// execute a task on that queue asynchronously
dispatch_async(myqueue, ^{
NSURL *url = [NSURL URLWithString:[urlstring stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];;
NSData *data = [NSData dataWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
Image.image = [UIImage imageWithData:data]; //UI updates should be done on the main thread
});
});
As mentioned by others, an Image Caching library like SDWebImage will help a lot because even with this implementation, you just push the download process to a background thread so the UI does not get stucked, but you are not caching anything.

Try this
[image setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.vbarter.com/images/content/1/9/19517.jpg"]]]];
For async downloading
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[image setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.vbarter.com/images/content/1/9/19517.jpg"]]]];
});
if url is dynamic then
NSString *stringUrl; // this can be any valid url as string
[image setImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:stringUrl]]]];

NSData *data = [NSData dataWithContentsOfURL:url];
will load imageData synchronous, that means main thread will be blocked .
Use the project on github:SDWebImage for image asynchronous loading and cache.

There's probably better libraries that do this now, but I have always been using this for my projects and it works well: AsyncImageView. There are other alternatives like SDWebImage
But basically, you don't want to use
NSData *data = [NSData dataWithContentsOfURL:url];
because it will block the main thread until the image is downloaded. To avoid this you might want to use something asynchronous, like the above two libraries.
For example, with AsyncImageView, it becomes as easy as:
myImageView.imageURL = someNSURL;

Related

Image not showing using Nsurlconnection Post method

I am using nsurlconnection in POST method and created four array for "see","buy","updated","image".Displayed in tableviewcell but "image" not showing. image in "url in png format".
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError* error;
json = [NSJSONSerialization JSONObjectWithData: mutableData
options:kNilOptions
error:&error];
NSLog(#"%#",json);
sellArray = [json valueForKeyPath:#"BranchByList.sell"];
buyArray = [json valueForKeyPath:#"BranchByList.buy"];
updataedArray = [json valueForKeyPath:#"BranchByList.updated"];
imageArray = [json valueForKeyPath:#"BranchByList.flag_image"];
[_datad reloadData];
}
tableview delegate methods are:
-(NSInteger)numberOfSectionsInTableView:(UITableView *) tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *) tableView numberOfRowsInSection:(NSInteger)section{
return [sellArray count];
return [buyArray count];
return [updataedArray count];
return [imageArray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
TableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:#"path" forIndexPath:indexPath];
cell.sellbl.text=[sellArray objectAtIndex:indexPath.row];
cell.buylbl.text=[buyArray objectAtIndex:indexPath.row];
cell.updatedlbl.text = [updataedArray objectAtIndex:indexPath.row];
cell.imglbl.image = [UIImage imageNamed:[imageArray objectAtIndex:indexPath.row]];
return cell;
}
-(void)tableView: (UITableView *) tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
}
You are directly assigning url to image! That will not work at all.
You need to first add the url to NSUrl and then convert the url in to data by using NSData and then assign the data to the image.
To accomplish it add below line of code in your code:
NSURL *url = [NSURL URLWithString:[imageArray objectAtIndex:indexPath.row]];
NSData *data = [NSData dataWithContentsOfURL:url];
cell.imglbl.image = [UIImage imageWithData:data];
I'm posting one more example for more understanding. I have a url and i need to display the image from that url to my device. For that m using the below line of code:
NSURL *url = [NSURL URLWithString:#"http://1.bp.blogspot.com/-9yd6LPL2N6U/VatsUdMffPI/AAAAAAAAAl4/Pq1S6Q20fy0/s1600/hello_world.gif"];
NSData *data = [NSData dataWithContentsOfURL:url];
_imgView.image=[UIImage imageWithData:data];
Above url is just a random url of a image taken from google.
Result:
You are calling image like,
cell.imglbl.image = [UIImage imageNamed:[imageArray objectAtIndex:indexPath.row]];
It is fine if image is available in your project otherwise you need to download it from url which you getting in response like,
NSData *data = [NSData dataWithContentsOfURL:#"you url"];
UIImage *img = [UIImage imageWithData:data];
cell.imglbl.image = img;
or you can use SDWebImage, greate third party library to caching the image.
hope this will help :)
Add SDWebImage
in your project and use this code
[cell.imglbl setImageWithURL:[NSURL URLWithString:[imageArray objectAtIndex:indexPath.row]]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
instead of
cell.imglbl.image = [UIImage imageNamed:[imageArray objectAtIndex:indexPath.row]];
return cell;
It seems like you set not an image to cell.imglbl.image, but the url of it..
cell.imglbl.image = [UIImage imageNamed:[imageArray objectAtIndex:indexPath.row]];
You can use some third party library like SDWebImage to asynchronous download image.
https://github.com/rs/SDWebImage
(Or download it synchronous like this
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]];
UIImage *image = [UIImage imageWithData:data];
)
Also I would recommend you to have a Dictionary to keep already downloaded images, where the keys will be the indexPaths of cells.
Hope it help :)

unable to use objectAtIndex property

im trying to load a set of images from web and display it on the screen within a collection view. Following is my code
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.layer.cornerRadius = 5;
NSURL *url = [NSURL URLWithString:
#"http://elatewiki.org/images/thumb/Google.png/120px-Google.png"];
UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
UIImageView *recipeImageView = (UIImageView *)[cell viewWithTag:100];
//recipeImageView.image = [UIImage imageNamed:[recipePhotos objectAtIndex:indexPath.row] ];
recipeImageView.image = [UIImage imageWithData: [NSData dataWithContentsOfURL:recipPhotoUrl[0] ]];
return cell;
}
but i have to use the objectAtIndex:indexPath.row property along with imageWithData so the image can be swiped . Is there any ways through which i can use objectAtIndex:indexPath.row along with NSData dataWithContentsOfURL ?
You can use this:
NSString *url_str = [NSString stringWithFormat: #"%#",[recipPhotoUrl objectAtIndex: indexPath.item]];
NSURL *url = [NSURL urlWithString:url_str];
recipeImageView.image = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
What's the for?
NSURL *url = [NSURL URLWithString:
#"http://elatewiki.org/images/thumb/Google.png/120px-Google.png"];
UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
Anyway, you were close to solution....
if (recipPhotoUrl.count > indexPath.row)
{
recipeImageView.image = [UIImage imageWithData: [NSData dataWithContentsOfURL:recipPhotoUrl[indexPath.row]]];
}
But still, you are doing this operations on the main thread and you, for sure, block the UI, the scroll will not be smooth.
It also not so sure as you're accessing the index without checking if the array has a sufficient dimension.
UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
should be placed in a common function.For example -(void)viewDidLoad, add a property reference to image .
recipeImageView.image = [UIImage imageWithData: [NSData dataWithContentsOfURL:recipPhotoUrl[0]]];
change to
recipeImageView.image = self.image;

get image faster than file URL

I'm creating a stack of images in my viewdidload method. The images are from PFFile's from parse so they contain the fileURL of my image data.
My problem is that these two lines of code are dramatically slowing down my app and killing my user experience:
//get scene object
PFObject *sceneObject = self.scenes[i];
//get the PFFile and filetype
PFFile *file = [sceneObject objectForKey:#"file"];
NSString *fileType = [sceneObject objectForKey:#"fileType"];
//check the filetype
if ([fileType isEqual: #"image"])
{
//get image
NSURL *imageFileUrl = [[NSURL alloc] initWithString:file.url];
NSData *imageData = [NSData dataWithContentsOfURL:imageFileUrl]; ********** these
imageView.image = [UIImage imageWithData:imageData]; ********************* lines
}
How do I get this image/these images (this is nested in a for loop) more quickly? I've already downloaded my PFObjects that contain the PFFiles and stored them locally.
I guess I really don't understand how file URL's operate.
Thank you.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSURL *imageFileUrl = [[NSURL alloc] initWithString:file.url];
NSData *imageData = [NSData dataWithContentsOfURL:imageFileUrl];
dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:imageData];
});
});
Have not tested but this is the gist. Get the file loading off the main queue and make it asynchronous. The UI will not be bogged down because as soon as this queue is dispatched it's going to return and keep evaluating the rest of your application.
I am using somethig like this:
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[imageFrame addSubview:activityIndicator];
activityIndicator.center = CGPointMake(imageFrame.frame.size.width / 2, imageFrame.frame.size.height / 2);
[activityIndicator startAnimating];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData * imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:thumb]];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:imageData];
img.image = image;
[imageOver addSubview:img];
[activityIndicator removeFromSuperview];
});
});

iOS UIImage Passes Old Image

In my app, Im using an API to get images from a server. Using the below code, it gets the images in order of size to replace themselves with better quality.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString: [NSString stringWithFormat:#"%#", [[[self.information objectForKey:#"images"]objectForKey:#"normal"] description]]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
self.shotImage = [UIImage imageWithData:imageData];
self.image.image = self.shotImage;
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString: [NSString stringWithFormat:#"%#", [[[self.information objectForKey:#"images"]objectForKey:#"hidpi"] description]]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
self.image.image = self.shotImage;
});
Also, if you press on the image it then takes you too another ViewController where the image is fullscreen.
However, even if I wait for the high quality one to load before I tap on it, in the PrepareForSegue Method, it still only passes the original low quality version.
See code below from PrepareForSegue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
FullSizeImageViewController *vc = [segue destinationViewController];
UIImage *img = [[UIImage alloc] init];
img = self.shotImage;
vc.shotImage = img;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString: [NSString stringWithFormat:#"%#", [[[self.information objectForKey:#"images"]objectForKey:#"hidpi"] description]]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
self.image.image = self.shotImage;
});
In this code looks like you miss this line:
self.shotImage = [UIImage imageWithData:imageData];

App crashes if null image URL is loaded in JSON object

I am populating a tableView with objects from a MySQL table via JSON.
The source data are introduced by many users in a web site form, and sometimes they don't introduce an image URL into a field.
The downloaded JSON object are shown in the tableView which rows are configured to show text, detail text and image.
If the object doesn't have an image URL, the app crashes, and I want to show a default image instead, to avoid the crash.
This is how am I loading the JSON data for the object's image:
NSMutableString *logo = [[NSMutableString alloc]initWithString:#"http://mujercanariasigloxxi.appgestion.eu/logos/"];
NSString *imageURL = [[categorias objectAtIndex:indexPath.row] objectForKey:#"strImagen"];
[logo appendString:imageURL];
NSURL *logoURL = [NSURL URLWithString:logo];
NSData *logoData = [NSData dataWithContentsOfURL:logoURL];
cell.imageView.image = [UIImage imageWithData:logoData];
What should be the best way to avoid the crash and to show a default image if the web site user doesn't include an image URL in the web form?
Try use a if-else condition, like
NSMutableString *logo = [[NSMutableString alloc]initWithString:#"http://mujercanariasigloxxi.appgestion.eu/logos/"];
NSData *logoData;
if([categorias objectAtIndex:indexPath.row] && [[categorias objectAtIndex:indexPath.row] objectForKey:#"strImagen"]){
NSString *imageURL = [[categorias objectAtIndex:indexPath.row] objectForKey:#"strImagen"];
[logo appendString:imageURL];
NSURL *logoURL = [NSURL URLWithString:logo];
logoData = [NSData dataWithContentsOfURL:logoURL];
}
else {
//load your default image here
logoData = //default logo data
}
cell.imageView.image = [UIImage imageWithData:logoData];
//set an activity indicator
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSString *imageURL = [[categorias objectAtIndex:indexPath.row] objectForKey:#"strImagen"];
if (imageURL.count>0){
[logo appendString:imageURL];
//declare logodata as nsdata
logoData=[NSData dataWithContentsOfURL:[NSURL URLWithString:logo]];
}
dispatch_sync(dispatch_get_main_queue(), ^{
//turn the activity indicator off
if(logoData!=nil)
cell.imageView.image = [UIImage imageWithData:logoData];
else
//set your default image.
});
});
Hope this might help you.
You may try checking whether imageurl is nil or in some cases it will come as null.
NSMutableString *logo = [[NSMutableString alloc]initWithString:#"http://mujercanariasigloxxi.appgestion.eu/logos/"];
NSString *imageURL = [[categorias objectAtIndex:indexPath.row] objectForKey:#"strImagen"];
if(imageURL != nil && ![imageURL isEqual:[NSNull null]])
{
[logo appendString:imageURL];
NSURL *logoURL = [NSURL URLWithString:logo];
NSData *logoData = [NSData dataWithContentsOfURL:logoURL];
cell.imageView.image = [UIImage imageWithData:logoData];
}
else{
cell.imageView.image = [UIImage imageNamed:#"Default_image"];
}

Resources