Downloading and saving an image from link in UIWebView - iphone

I am trying to save an image to the photo library from a website which is opened in an uiwebview.The link is not just an image link where NSURLConnection can be used to download.I want to achieve the download by long pressing the image in UIWebView just as it can be done in safari. How can i achieve this..is it possible??

NSURL *url = [NSURL URLWithString:link];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
NSURLResponse *response = NULL;
NSError *requestError = NULL;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&requestError];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
the response string contains complete information

Sorry to ask, but why do you use an UIWebView to only load an image. The UIImageView class constructor imageWithContentsOfURL: would do the job perfect.
Then you can just use an UIPopoverController for presenting a UIViewController with an UIButton calling UIImageWriteToSavedPhotosAlbum (http://goo.gl/uAJYS) to save the UIImage from your UIImageView directly into the users camera roll.
For Optimisation use an UITableViewController instead of the UIViewController - more the default iOS look&feel - and present the UIPopoverController with a small delay by overwriting the UIResponder methods on the UIImageView.
// EDIT: If you really mean how to get the exact behaviour of the Safari to save any image in the dom tree, i am a bit stumped. Maybe someone else can contribute some information on that.

Related

Taking time to load the image from URL to UIImageview

I am using this code for displaying the image from URL to UIImageview
UIImageView *myview=[[UIImageView alloc]init];
myview.frame = CGRectMake(50, 50, 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];
But the problem is that its taking too long time to display the image in imageview.
Please help me...
Is there any method to fast the process...
Instead of dispatch_async, Use SDWebImage for caching the images.
This is best I have seen...
The problem of dispatch_async is that if you lost focus from image, it will load again. However SDWebImage, Caches the image and it wont reload again.
The answers given to me on my own question Understanding the behaviour of [NSData dataWithContentsOfURL:URL] inside the GCD block does makes sense.So be sure that if you use [NSData dataWithContentsOfURL:URL] inside the GCD(as many developers do these days) is not a great idea to download the files/images.So i am leaning towards the below approach(you can either use NSOperationQueue).
Load your images using [NSURLConnection sendAsynchronousRequest:queue:completionHandler: then use NSCache to prevent downloading the same image again and again.
As suggested by many developers go for SDWebimage and it does include the above strategy to download the images files .You can load as many images you want and the same URL won't be downloaded several times as per the author of the code
EDIT:
Example on [NSURLConnection sendAsynchronousRequest:queue:completionHandler:
NSURL *url = [NSURL URLWithString:#"your_URL"];
NSURLRequest *myUrlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:myUrlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if ([data length] > 0 && error == nil)
//doSomething With The data
else if (error != nil && error.code == ERROR_CODE_TIMEOUT)
//time out error
else if (error != nil)
//download error
}];
Use Dispatch queue to load image from URL.
dispatch_async(dispatch_get_main_queue(), ^{
});
Or add a placeholder image till your image gets load from URL.

AFImageRequestOperation with SDWebImage issue

I use AFImageRequestOperation to download some icons, meanwhile use SDWebImage to download some pics for main view. Each AFImageRequestOperation is added to my publicOperationQueue defined in app delegate, its maxConcurrentOperationCount is set to 10. Strange thing is that sometimes one or two of my 10+ icons will be replaced by some pic in main view, which should be downloaded by SDWebImage. And when I set a larger maxConcurrentOperationCount which is bigger than my icon counts, it works fine. I doubt if it has something to do with multiple NSOperationQueues sharing some resources and maxConcurrentOperationCount. Any one could help?
//below is the icon downloading code
//============================//
for(NSString *url in picUrls)
{
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[urlRequest setHTTPShouldHandleCookies:NO];
[urlRequest addValue:#"image/*" forHTTPHeaderField:#"Accept"];
AFImageRequestOperation *requestOperation = [[AFImageRequestOperation alloc] initWithRequest:urlRequest];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){
NSString *imageName = trimNilOrNuLL([url lastPathComponent]);
if(imageName.length > 0)
{
NSData *imageData = UIImagePNGRepresentation(responseObject);
[imageData writeToFile:[path stringByAppendingPathComponent:imageName] atomically:YES];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error){
NSLog(#"%#",error);
}];
[[AppShare appDelegate].publicOperationQueue addOperation:requestOperation];
}
//============================//
and for SDWebImage, I use - (void)setImageWithURL:(NSURL *)url method in UIImageView+WebCache category to download pic
OK,From the question found that you are using AFNetworking .Then for image downloading why dont you use the UIImageView Extention of AFNetworking?
You dont have to implement any queue or anything for this
some code like this is enough i think
[self.imageview setImageWithURL:url placeholderImage:nil];

Get Facebook profile pic using 3.0 SDK

I'm having trouble getting the user's profile pic with the new Facebook SDK. All the answers on here use methods from the old SDK that no longer work.
I've tried using the FBProfilePictureView recommended in Facebook's tutorial, but this picture doesn't get cached and I don't think it can be converted into a UIImage.
Can anyone please provide some help? Thanks!
OK, I finally got this using the following:
imageData = [[NSMutableData alloc] init]; // the image will be loaded in here
NSString *urlString = [NSString stringWithFormat:#"http://graph.facebook.com/%#/picture?type=large", user.id];
NSMutableURLRequest *urlRequest =
[NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:2];
// Run request asynchronously
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest
delegate:self];
if (!urlConnection)
NSLog(#"Failed to download picture");
Then I used -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data and -(void)connectionDidFinishLoading:(NSURLConnection *)connection to put the image together.
Best solution i've found:
I've used UIImage from AFNetworking https://github.com/AFNetworking/AFNetworking. It handles redirect and caching so you can fetch profile picture for every user id you have.
NSString *imageUrl = [NSString stringWithFormat:#"http://graph.facebook.com/%#/picture", ((NSDictionary<FBGraphUser> *) [self.friends objectAtIndex: indexPath.row]).id];
[friendCell.imageView setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:#"profile.jpg"]];
Use https://github.com/rs/SDWebImage to cache the image. The URL to request the image should be
NSString *string = [NSString stringWithFormat:#"https://graph.facebook.com/%#?fields=picture", userid];
Use the link:
https://graph.facebook.com/me?fields=picture
to get the current user's profile picture.
Facebook provides the Graph API explorer tool which can come in handy when you want to try queries or to check the returned output.
Here's a link to the User API Reference.
If your problem is related to "self.userPofilePicture.profileID = user.id;".
Then self.userProfilePicture return UIView so just take View and display in it.
Don't forgot add class FBProfilePictureView in Identity Inspector as well as [FBProfilePictureView class] to AppDelegate implementation file.
I hope this will helpful.

NSURLConnection sendSynchronousRequest - background to foreground

I m using sendSynchronousRequest to get the data from the server. I know that synchronous will wait until the data received for that request.
But the problem comes when user by mistake enters some non-existing url and than tries to get response. In this case, if user goes in to background and than comes into foreground it shows only black screen. It only shows status bar. Also its not showing any background application. I have to press Home button to come out of my application.
On simulator, After 1+ minute it shows me the message that "Request time out" (No crash).
On Device, within 1 min application get crashes.
Any suggestion. Any Help. This is really a serious issue in my app.
Thanks.
Just like Julien said, the watchdog is killing your app. To answer some questions:
why does this happen only on the simulator?
Because when you're debugging the watchdog leaves your app alone, it can take time.
why does this happen only when the user enters a wrong url?
Because of the system timeout, the system will keep trying for 60 secs if it can't find a server.
so the problem is synchronous vs asynchronous?
No, the problem is the thread, you can do the same operation in a background thread, just don't do it on the main thread and the watchdog will leave you alone.
why is the screen black when the app comes up?
Remember, you are making blocking stuff on the main thread, the thread that draws...
Hope that was all. Let me know if I missed something.
Why not setting a timeout for your connection?
NSString *urlString = TEST_CONNECTION;
NSError *error = nil;
NSHTTPURLResponse *response = nil;
NSURLRequest *request = [NSURLRequest
requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:5.0];
NSData *conn = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
This should release the synchronous waiting after a number of seconds, which should solve your problem without going with an asynchronous call (which sometimes isn't the proper solution)
I know this works properly because this is how I check if I am connected to a certain VPN (where reachability flags totally fail).
you should take a look to this article: https://developer.apple.com/library/ios/#qa/qa1693/_index.html
iOs contains a watchdog, if your application is blocked to much time on an operation on the main thread, this one will be killed. (for more details about Watchdog: http://en.wikipedia.org/wiki/Watchdog_timer)
So if you want to download something, don't download it on the main thread.
RELATE
UIImage *image = [self.imgCache objectForKey:urlString];
if(!image){
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:60.0];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
NSLog(#"%#",response);
UIImage *img = [UIImage imageWithData:data];
//
if(img)
{
dispatch_sync(dispatch_get_main_queue(), ^{
[self.imgCache setObject:img forKey:urlString];
completionBlock(img);
});
}
});
}
else{
completionBlock(image);
}
use ASIHttpRequest class instead of NSURLConnection , its nothing but wrapper around NSURLConnection and has very simple callbacks , you can also set time to complete a request. Please go through this link for more info http://allseeing-i.com/ASIHTTPRequest/
I think you first have to test user data whether it is correct or not and than only if it is correct, sends the request otherwise prompt user that "please enter correct data"...
or
when your parsing of data in response failed. You can also make protocol delegate method i.e FinishWithError so that you come up with your last UI.
Try this one:
#import "ASIHTTPRequest.h"
//In a method
[self performSelectorInBackground:#selector(DownLoadImageInBackground:) withObject:imgUrlArr];
-(void) DownLoadImageInBackground:(NSArray *)imgUrlArr1
{
NSURL * url = [Image URL];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
-(void)requestFailed:(ASIHTTPRequest *)request
{
NSLog(#"URL Fail : %#",request.url);
NSError *error = [request error];
// you can give here alert too..
}
-(void)requestFinished:(ASIHTTPRequest *)request
{
NSData *responseData = [request responseData];
UIImage *imgInBackground = [[UIImage alloc]
initWithData:responseData];
[imageView setImage: imgInBackground];
}
This might help you: I am also loading a number of images at one time, so images that have no proper data show a black screen. To avoid this, try to resize your imageview.
You could check the reachability of the URL before starting the request.
Apple has Reachability Methods to do so. But its easier to use a wrapper. E.g. ASIReachability.
I think the application crashing because you does not get any data when user enters wrong URL and you are using this 'returned' nil NSData to do stuffs.
I think this will fix your problem
NSData *data=[NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if(data!=nil){
///
} else {
NSLog(#"NO DATA");
}

Loading Image into UIImageView using NSURLConnection

Hey all. I'm really new at this obj-c/xcode stuff. I'm trying to load the background of my xib file. To do this i'm using a UIImageView and populating that with an image I found from the net. the problem with that is that it's REALLY slow. Feels like it's crashing but it's not. I was told to use an NSURLConnection to fix the problem but don't know how. Here's the code i was using previously.
wallpaper.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://mysite.com/mobile/wallpaperR.asp?id=%i",customerID]]]];
How do i translate the above code into the NSURLConnection equivalent?
NSURLConnection will download the data in a new thread, so you app will feel much faster.
It is pretty easy to implement but it does require you to understand the concept of delegation.
I have a useful class I created to handle image downloads on separate threads, I will share the code with you, with comments to let you know what is going on:
AsyncImage.h
AsyncImage.m
If you need help implementing it just leave a comment and I can help you get it working, I remember this used to be pain for me too when I started developing.
You need to do parsing for this as you are using the webservice.Like this
-(void)startParsingForPhotoAlbumList:(NSString*)providerIdString
{
NSString *urlString = [NSString stringWithFormat:#"http://YourUrl/showalbumxml.php?id=%#&show=show",providerIdString];
NSURL *xmlURL = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:xmlURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0]autorelease];
NSURLResponse *returnedResponse = nil;
NSError *returnedError = nil;
NSData *itemData = [NSURLConnection sendSynchronousRequest:request returningResponse:&returnedResponse error:&returnedError];
self.xmlParser = [[NSXMLParser alloc] initWithData:itemData];
[xmlParser setDelegate:self];
[xmlParser parse];
}
and need to implement parser's delegate method as an example.
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
if ([[[resultArray objectAtIndex:1]objectForKey:#"Transaction"]isEqualToString:#"Myapp/snaps"])
{
[(LoginViewController *)obj getRegisterResult:resultArray];
}
}
Then in your Viewcontroller access the data,from parsing you need to pass objects,using array or dictionary.
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:itemImagePath]];
UIImage *image = [[UIImage alloc] initWithData:imageData];
There is an example which may help:
NSURLConnection loading image example