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];
Related
I am uploading the image from the ImagePicker and once the image is upload on the server I show it from URL. So from local image to URL image, there comes a blink, which I want to avoid but I am unable to fix it. Any suggestion will be really helpful. I am adding the code below:
- (void)setDataOnCell:(NSDictionary *)dict {
self.messageTimeLabel.text = [CommonUtils checkForNUllValue:[dict valueForKey:#"msg_time"]];
if (![[CommonUtils checkForNUllValue:[dict valueForKey:#"msg_status"]] isEqualToString:#"Read"]) {
self.messageTickImageView.image = [UIImage imageNamed:#"check_delivered_icon"];
self.messageStatusLabel.textColor = [UIColor colorWithRed:166.0f/255.0f green:166.0f/255.0f blue:166.0f/255.0f alpha:1.0];
}
else {
self.messageTickImageView.image = [UIImage imageNamed:#"check_read_icon"];
self.messageStatusLabel.textColor = [UIColor colorWithRed:254.0f/255.0f green:223.0f/255.0f blue:224.0f/255.0f alpha:1.0];
}
self.messageStatusLabel.text = [CommonUtils checkForNUllValue:[dict valueForKey:#"msg_status"]];
if ([[NSString stringWithFormat:#"%#", [dict valueForKey:#"attachment_type"]] isEqualToString:#"local_img"]){
self.messageImageview.image = [dict valueForKey:#"attachment"];
}
else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
NSURL *imageURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#", [NSString stringWithFormat:#"%#", [dict valueForKey:#"attachment"]]]];
NSData *urlData = [NSData dataWithContentsOfURL:imageURL];
//This is your completion handler
dispatch_sync(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:urlData];
self.messageImageview.image = image;
});
});
}
}
first of all you need to set a default image on this image view after that you call image by url and set on this
NSOperationQueue *queueThumbnl = [[NSOperationQueue alloc] init];
[queueThumbnl setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];
[queueThumbnl addOperationWithBlock:^{
// Background work
NSURL *imageURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#", [NSString stringWithFormat:#"%#", [dict valueForKey:#"attachment"]]]];
NSData *urlData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:urlData];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:self.messageImageview, #"messageImageview", urlData, #"imageData", nil];
[self performSelectorOnMainThread:#selector(mainThreadUIUpdate:) withObject:dict waitUntilDone:YES];
// [self updateThumbnailOnMainThread:anItem setImageTo:cell];
}];
-(void)mainThreadUIUpdate:(NSDictionary *)dict
{
UIImageView *messge = [dict objectForKey:#"messageImageview"];
UIImage *image = [dict objectForKey:#"image"];
[messge.imageView setImage:image];
[cell.imageView setNeedsDisplay:YES];
}
I have a block to download an convert an image to UIImage. this is my code
-(UIImage *)GetProfileImage
{
NSString *strimgBaseUrl=[[[NSBundle mainBundle] infoDictionary] objectForKey:#"BaseImageURL"];
NSString *strFilePath=[dm.dictUserProfile valueForKey:#"ImagePath"];
NSString *strImgURL=[NSString stringWithFormat:#"%#%#",strimgBaseUrl,strFilePath];
__block UIImage *imgProf=nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString:strImgURL];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
imgProf= image;
if(image!=nil){
imgProf=image;
}
});
});
return imgProf;
}
But this block is never execute.It goes to return __block UIImage *imgProf=nil; Why is that? Please help me.
Thanks
Code is working ok. This is the purpose of dispatch_async.
Form the documentation
#function dispatch_async
Calls to dispatch_async() always return immediately after the block has been submitted, and never wait for the block to be
invoked.
This is the opposite of dispatch_sync.
You could change the GetProfileImage like this
- (void)setProfileImageForImageView:(UIImageView *)imageView {
NSString *strimgBaseUrl=[[[NSBundle mainBundle] infoDictionary] objectForKey:#"BaseImageURL"];
NSString *strFilePath=[dm.dictUserProfile valueForKey:#"ImagePath"];
NSString *strImgURL=[NSString stringWithFormat:#"%#%#",strimgBaseUrl,strFilePath];
__block UIImage *imgProf=nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString:strImgURL];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
imgProf= image;
if(image!=nil){
// imgProf=image;
imageView.image = image;
}
});
});
}
Use a completion block instead, rather than returning from function:
-(void)GetProfileImageWithCompletion:(void (^)(UIImage *profileImage))completionHandler
{
NSString *strimgBaseUrl=[[[NSBundle mainBundle] infoDictionary] objectForKey:#"BaseImageURL"];
NSString *strFilePath=[dm.dictUserProfile valueForKey:#"ImagePath"];
NSString *strImgURL=[NSString stringWithFormat:#"%#%#",strimgBaseUrl,strFilePath];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *imageURL = [NSURL URLWithString:strImgURL];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
if(image!=nil && completionHandler){
completionHandler(image);
}
});
});
}
And use like this:
[self GetProfileImageWithCompletion:^(UIImage *profileImage)
{
//if image exists assign to image view
}
];
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];
});
});
I am fetching URL from web, and I want to show any message if image view can't get image from given URL.
Here is my Code.
NSString * image1 = [WebArray objectForKey:#"image_url"];
NSString * image2 = [[tempArray objectAtIndex:0]objectForKey:#"user_image"];
dispatch_queue_t imageQueue = dispatch_queue_create("Image Queue", NULL);
dispatch_async(imageQueue, ^{
NSURL *url = [NSURL URLWithString:image1];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
NSURL *url1 = [NSURL URLWithString:image2];
NSData *imageData1 = [NSData dataWithContentsOfURL:url1];
UIImage *image11 = [UIImage imageWithData:imageData1];
dispatch_async(dispatch_get_main_queue(), ^{
[user_image setImage:image];
[self.tag_user_img setImage:image11];
});
});
check image view is empty or not using
if(CGSizeEqualToSize(imageView.image.size, CGSizeZero))
{
show alert here....
}
dispatch_async(dispatch_get_main_queue(), ^{
if(!image)
{
// show your message
}
else
{
[user_image setImage:image];
}
});
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;