Asynchronous image download succeeded but image does not appear - ios

I am writing an app that displays images from url in a view. The idea is that when the view appears, image is dowloaded and it actualizes a UIImamgeView in the view.
I am using a Asyncrounse method in this way:
-(void)downloadASyncro:(NSString*)urlLink{
NSURL * imageURL = [NSURL URLWithString:urlLink];
[self downloadImageWithURL:imageURL completionBlock:^(BOOL succeeded, UIImage *image) {
if (succeeded) {
NSLog(#"scaricaImmagineASyncro Succeded= %#",image);
picView.image = image;
}
else {
//default image
picView.image = [UIImage imageNamed:#"icon_old.jpg"];
}
}];
}
the downloadImageWithURL method is:
- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if ( !error )
{
UIImage *image = [[UIImage alloc] initWithData:data];
completionBlock(YES,image);
} else{
completionBlock(NO,nil);
}
}];
}
When I call the method:
[self downloadASyncro:link];
and the operation sees end with success (NSLOG), picView.image = image; should actualize the view showing the image downloaded , should not it? But immage does not appear...
Any idea? Thanks in advance.

Related

Updating image and saving it in dictionary

I am getting image as url from dictionary on ViewController A and I have passed that dictionary to ViewController B.I want that if the user has updated the image then it shows the updated image else it shows the previous image and I am doing the following code for it .Kindly check and tell why is it not working as desired and showing the previous image only in every case.
-(void)showUserImage:(NSURL*)imgUrl
{
[ConnectionManager setSharedCacheForImages];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:imgUrl];
NSURLSession *session = [ConnectionManager prepareSessionForRequest];
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
if (cachedResponse.data) {
UIImage *downloadedImage = [UIImage imageWithData:cachedResponse.data];
dispatch_async(dispatch_get_main_queue(), ^{
_profileImageView.image = downloadedImage;
});
} else {
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
if(res.statusCode == 200){
dispatch_async(dispatch_get_main_queue(), ^{
_profileImageView.image = [UIImage imageWithData:data];
});
}
}];
[task resume];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
if(_profileImageView.image == [_detailsDictionary valueForKey:#"ProfilePictureUrl"]) {
NSLog(#"Th url of image is %#",[_detailsDictionary valueForKey:#"ProfilePictureUrl"]);
}
else {
_profileImageView.image = image;
UIImage *updatedImage = _profileImageView.image;
NSData *imageData = UIImageJPEGRepresentation(updatedImage, 100);
NSString *strEncoded = [imageData base64EncodedStringWithOptions:0];
[_detailsDictionary setObject:strEncoded forKey:#"ProfilePictureUrl"];
[self dismissViewControllerAnimated:YES completion:nil];
}
}
#Dirtydanee, He is absolutely correct, you are doing incompatible comparison between Url and UIImage. So please correct this with following code.
NSData *data1 = UIImagePNGRepresentation(previousImage);
NSData *data2 = UIImagePNGRepresentation(currentImage);
if([data1 isEqualToData:data2]) {
//Do something
} else {
//Do something
}
Convert images into NSData and compare the data.
If you want bit-by-bit comparison Please look at the following link:
Generate hash from UIImage
The problem seems to be in this line:
if(_profileImageView.image == [_detailsDictionary valueForKey:#"ProfilePictureUrl"]) {
You are trying to compare the _profileImageView.image, what is UIImage, with [_detailsDictionary valueForKey:#"ProfilePictureUrl"], what is NSURL instance, coming from the dictionary.
What you could do instead, is checking if the picked image and the profileImage is the same.
if(_profileImageView.image == image) {
// etc..
To clear previously cached images, just call:
[[NSURLCache sharedURLCache] removeAllCachedResponses];
Hope this helps!

Objective-C: Get Image from JSON

I am trying to learn web service on iOS.
I'm starting of from getting an image from a JSON api link.
I've used the code below but the image is not displaying and I'm getting warning that says
Incompatible pointer types assigning to 'UIImage * _Nullable' from 'NSSting * _Nullable'
My code
NSURL *urlAdPop = [NSURL URLWithString:#"JSON LINK HERE"];
NSURLRequest *request = [NSURLRequest requestWithURL:urlAdPop];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
if (data.length > 0 && connectionError == nil)
{
NSDictionary *AdPopUp = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
popUpBanner.image = [[AdPopUp objectForKey:#"ad_image"] stringValue];
popUpAdURL = [AdPopUp objectForKey:#"ad_link"];
}
}];
popUpBanner.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:popUpAdURL]];
popUpBanner.hidden = NO;
popUpBanner.layer.cornerRadius = 9;
popUpBanner.clipsToBounds = YES;
popUpBanner.userInteractionEnabled = YES;
[self.view addSubview:popUpBanner];
You need to write your code inside block after you get response from webservice.
NSURL *urlAdPop = [NSURL URLWithString:#"JSON LINK HERE"];
NSURLRequest *request = [NSURLRequest requestWithURL:urlAdPop];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
if (data.length > 0 && connectionError == nil)
{
NSDictionary *AdPopUp = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
popUpBanner.image = [[AdPopUp objectForKey:#"ad_image"] stringValue];
popUpAdURL = [AdPopUp objectForKey:#"ad_link"];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:popUpAdURL]];
dispatch_async(dispatch_get_main_queue(), ^{ // get main thread to update image
popUpBanner.image= image
popUpBanner.hidden = NO;
popUpBanner.layer.cornerRadius = 9;
popUpBanner.clipsToBounds = YES;
popUpBanner.userInteractionEnabled = YES;
[self.view addSubview:popUpBanner];
});
}
}];
popUpBanner.layer.cornerRadius = 9;
popUpBanner.clipsToBounds = YES;
popUpBanner.userInteractionEnabled = YES;
popUpBanner.hidden = YES;
[self.view addSubview:popUpBanner];
NSString* strURL=#"JSON LINK HERE";
NSString* webStringURL = [strURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *urlAdPop = [NSURL URLWithString:webStringURL];
NSURLRequest *request = [NSURLRequest requestWithURL:urlAdPop];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response,
NSData *data, NSError *connectionError)
{
if (data.length > 0 && connectionError == nil)
{
NSDictionary *AdPopUp = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
popUpAdURL = [AdPopUp objectForKey:#"ad_link"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",[AdPopUp objectForKey:#"ad_image"]]]];
if (imgData)
{
UIImage *image = [UIImage imageWithData:imgData];
if (image)
{
dispatch_async(dispatch_get_main_queue(), ^{
popUpBanner.image = image;
popUpBanner.hidden = NO;
});
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
});
}
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
});
}
});
}
}];
Perfect way to display image!
Hope It will help you :)
If you need to deal with images comes from web response then you can use SDWebImage library from GitHub.
In its read me page they have also provided the way how you can achieve it.
#import <SDWebImage/UIImageView+WebCache.h>
[self.YourImageView sd_setImageWithURL:[NSURL URLWithString:#"http://yourimagePath/.../"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
Thats it !
Firstly,check if that url available in browser. If yes,check if your app accept HTTP(not HTTPS). You can set app accept like this:
You are adding popUpBanner in view after getting image from server. so you have to initialize it before in viewdidload and need to set it's frame.
Then set image to popUpBanner from completion handler of web service on main thread. And make sure that you have to set image not image name string!
Below line is wrong, it is trying to set string to imageview which is not possible.
popUpBanner.image = [[AdPopUp objectForKey:#"ad_image"] stringValue];
get image from image url provided by service side and use image name that you get in response.
And make sure that you are getting image object using breakpoint.
Hope this will help :)
###require suppurate api to load image.
want to attach the link and image name together as to reach. thus two strings are needed to store each the api and the image name.###
s=[[mutarray objectAtIndex:index]valueForKey:#"image"];
NSString *f=[NSString stringWithFormat:#"http://iroidtech.com/wecare/uploads/news_events/%#",s];
NSURL *g=[[NSURL alloc]initWithString:f];
data=[NSMutableData dataWithContentsOfURL:g];
self.imgvw.image=[UIImage imageWithData:data];
_descrilbl.text=[[mutarray objectAtIndex:index]valueForKey:#"image"];

Instagram photo to UIImageView

can i show an instagram photo on my UIImageView?
I was looking for media id and other options, but i can't find the format and the way to show this image for example:
https://www.instagram.com/p/9W-K0wtq3v/
You can get direct link to image using http://api.instagram.com/oembed?url= . After that, downloading the image from that URL & displaying it in UIImageView is fairly simple. I have edited my answer to this one as it works without integrating Instagram API or parsing the web page for URL to file.
Add the following to methods to your View Controller. I have added explanation in comments.
- (void)getDirectURLToLink:(NSString *)urlStr completionBlock:(void (^)(BOOL succeeded, NSString *imageLink))completionBlock
{
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if ( !error )
{
//Convert data to dictionary as it is JSON. You can view json response for your url at http://paste.ubuntu.com/14437288/
NSError *error1;
NSMutableDictionary * innerJson = [NSJSONSerialization
JSONObjectWithData:data options:kNilOptions error:&error1
];
//Send the direct url to block
completionBlock(YES,[innerJson objectForKey:#"thumbnail_url"]);
} else{
//request failed
completionBlock(NO,nil);
}
}];
}
- (void)downloadImageWithURL:(NSString *)urlStr completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock
{
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if ( !error )
{
//cnvert data to uiimage
UIImage *image = [[UIImage alloc] initWithData:data];
completionBlock(YES,image);
} else{
//download failed
completionBlock(NO,nil);
}
}];
}
(But since sendAsynchronusRequest is deprecated in iOS 9.0, you should use [NSURLSession dataTaskWithURL])
Now you have set up the web request part of the file. To utilize these services, Add following method to your Viewcontroller:
-(void) getImageForPostURL: (NSString *)postURL
{
NSString *baseURL = #"http://api.instagram.com/oembed?url=";
NSString *directLinkRequestURL = [NSString stringWithFormat:#"%#%#",baseURL,postURL];
//Request Direct URL to file from your post url
[self getDirectURLToLink:directLinkRequestURL completionBlock:^(BOOL succeeded, NSString *imgDirectURL) {
if (succeeded) {
//Direct link retrieved
//Get image
[self downloadImageWithURL:imgDirectURL completionBlock:^(BOOL succeeded, UIImage *image) {
if (succeeded) {
// change the image where you want, it has been downloaded
_imgView.image = image;
}
}];
}
else
{
//Error
//Link could not be retrieved
}
}];
}
All this work is not for vain. Now, You are all set to go. All you need is a URL to instagram post and you will be able to download your image just by calling this one line:
[self getImageForPostURL:#"https://www.instagram.com/p/9W-K0wtq3v/"]; //Give your post url as parameter here
I think: it will have two ways to achieve your goal
*First: parse link web Instagram. If you view source your link give: you will find direct link to image:
https://igcdn-photos-b-a.akamaihd.net/hphotos-ak-xfp1/t51.2885-15/e35/10729433_781480525295113_239273684_n.jpg
So you can parse web and find:
<meta property="og:image" content="
for direct link.
Second: You can reference here:
https://instagram.com/developer/endpoints/media/
You enroll developer instagram and learn how to use Instagram API end points.

How to display images from dropbox in UIImageView

I am using DBChooser in my application to import images from dropbox, I am getting image url like & to dasplay the image in UIImageView i have following code
UIImageView *imageView=[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"https://www.dropbox.com/s/7qey2let40eb9je/PRELIMINARY_FORM_2.jpg"]]];
[self.view addSubview:imageView];
but the image is not showing in application. please help me how to display the dropbox image in UIImageView, is it issue of https OR what .
See this reference: https://cantonbecker.com/etcetera/2014/how-to-directly-link-or-embed-dropbox-images/
Short answer: append raw=1 as querystring value to your image url
Let's try:
+ (void) downloadImage : (NSURL*) url withCallBack:(DownloadCallbackBlock)callback
{
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSHTTPURLResponse *httpresponse = (NSHTTPURLResponse *)response;
if (httpresponse.statusCode == 200)
{
callback(error,data);
}
else
{
//error
}
}];
}
And I use it:
[DownloadManager downloadImage:url withCallBack:^(NSError *error, NSData *data){
if (data)
{
UIImage *image = [[UIImage alloc]initWithData:data];
[_arrImages addObject:image];
dispatch_async(dispatch_get_main_queue(), ^{
[self processAddImage];
});
}

How to tell if blocks in loop all have completed executing?

I have a loop set up that downloads a series a images which I will later use for to animate using the animationImages property of UIImageView. I would like to know when all the blocks inside my loops have finished executing so I could begin the animation, and was wondering how I may be able to tell when they are finished completing? Thanks!
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
}];
}
//When I know all the blocks have finished downloading, I will then to animate the downloaded images.
Edit: having issue with Error -999
I am encountering the following issue when executing the code in the provided answer: Domain=NSURLErrorDomain Code=-999 "The operation couldn’t be completed. (NSURLErrorDomain error -999.)"
A quick search reveals that Error -999 means "another request is made before the previous request is completed" ... which is certainly the case here since I am making several requests in quick succession. The recommended fix suggested here didn't work for me as it will only successfully download one UIImage (the last one requested) , with the previous ones failing. I was wondering if there is workaround here or in AFNetworking that I ought to consider? Thanks!
Edit 2: working code based on #David's solution
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:imageRequest];
requestOperation.responseSerializer = [AFImageResponseSerializer serializer];
dispatch_group_enter(group);
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Response: %#", responseObject);
UIImage *retrivedImage = (UIImage *)responseObject;
[self.downloadedUIImages addObject:retrivedImage];
dispatch_group_leave(group);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Image error: %#", error);
dispatch_group_leave(group);
}];
[requestOperation start];
counter ++;
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(#"Horray everything has completed");
NSLog(#"What is here %#", self.downloadedUIImages);
NSLog(#"Done");
});
Create a dispatch group, in the for loop enter the group, in the completion block leave the group. Then you can use dispatch_group_notify to find out when all blocks have completed:
dispatch_group_t group = dispatch_group_create();
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
dispatch_group_enter(group);
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
dispatch_group_leave(group);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
dispatch_group_leave(group);
}];
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// do your completion stuff here
});
Count how many you've completed. The challenging part is making it thread safe. I recommend creating an atomic counter class for that.
Generic solution!
+ (void)runBlocksInParallel:(NSArray *)blocks completion:(CompletionBlock)completion {
AtomicCounter *completionCounter = [[AtomicCounter alloc] initWithValue:blocks.count];
for (AsyncBlock block in blocks) {
block(^{
if ([completionCounter decrementAndGet] == 0) {
if (completion) completion();
}
});
}
if (blocks.count == 0) {
if (completion) completion();
}
}
NSMutableArray *asyncBlocks = [NSMutableArray array];
for (PFObject *pictureObject in objects){
[asyncBlocks addObject:^(CompletionBlock completion) {
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
} completion:completion];
}];
}
[BlockRunner runBlocksInParallel:[asyncBlocks copy] completion:^{
//Do your final completion here!
}];
Set up a property and initialize it to the number of cycles - objects.count. In the completion of the block, lower the number down. When you reach zero, you are done.
for (PFObject *pictureObject in objects){
PFFile *imageFile = [pictureObject objectForKey:#"image"];
NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
[tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
[self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
if([[objects lastObject] isEqual:pictureObject]) {
[self animateImages];
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Error %#", error);
if([[objects lastObject] isEqual:pictureObject]) {
[self animateImages];
}
}];
}
- (void)animateImages {
//do animation here.
}

Resources