Download using NSURLConnection - ios

I have a UIImageView that is displaying an image using a URL, I have a download button that brings up a UIActionSheet which will then download the file using the URL i want to know how to do the coding for the download part of it using NSURLConnection.
- (IBAction)DownloadClick:(id)sender {
UIActionSheet *Action = [[UIActionSheet alloc]
initWithTitle:#"Options"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Download", nil];
[Action showInView:self.view];
}
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) { //The Download code will go here This is where i need ur help
}
The Url is saved in a string named "Url".

I don't think you tried Google for this. Anyway, here is your code and don't forget to add NSURLConnectionDataDelegate,
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) { //The Download code will go here This is where i need ur help
//-------------------------------------------------------
NSURL *url = [NSURL URLWithString:#"your_data_url"];
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
NSLog(#"succeed...");
} else {
NSLog(#"Failed...");
}
//-------------------------------------------------------------------
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
}

Make use of asynchronous request for image download. It can also help you identify errors, if any during image downloading.
NSURL* url = [NSURL URLWithString:#"http://imageAddress.com"];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
UIImage* image = [[UIImage alloc] initWithData:data];
// do whatever you want with image
}
}];

If you need synchronous download you can try this code:
NSURL *imageUrl = [NSURL URLWithString:#"http://site.com/imageName.ext"];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
UIImage *image = [[UIImage alloc] initWithData:imageData];
Now you have an image that you can use.
If you need an asynchronous request I suggest you to read the NSURLConnectionDataDelegate, that helps you handle the download of the file.

Related

NSUrlConnection Delegate methods are not getting called from helper class

I have to do SSL pinning so need to verify server side SSL certificate.
SO I have to use NSURL delegates. I have a helper class in which I have created method which returns me login response:
- (NSData *)sendSynchronousRequest:(NSString *)strNewLoginRequest
returningResponse:(NSURLResponse **)response
error:(NSError **)error {
NSMutableURLRequest *finalRequest = nil;
NSURL *url= [NSURL URLWithString:const_url];
finalRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
NSData *requestData = [NSData dataWithBytes:[strLoginRequest UTF8String] length:[strLoginRequest length]];
self.connection = [[NSURLConnection alloc] initWithRequest:finalRequest delegate:self startImmediately:NO];
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
[self.connection unscheduleFromRunLoop:currentRunLoop forMode:NSDefaultRunLoopMode];
[self.connection scheduleInRunLoop:currentRunLoop forMode:#"connectionRunLoopMode"];
[self.connection start];
while ([currentRunLoop runMode:#"connectionRunLoopMode" beforeDate:[NSDate distantFuture]]);
return self.mutableResponse;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.response = response;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
self.mutableResponse = [[NSMutableData alloc]init];
[self.mutableResponse appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
dispatch_async(dispatch_get_main_queue(), ^{
if (loadingView)
{
[loadingView removeView];
}
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Failure" message:#"Network Failure" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
});
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (loadingView)
{
[loadingView removeView];
}
self.resultString = [[NSString alloc] initWithData:self.mutableResponse encoding:NSASCIIStringEncoding];
}
and I am calling this method from another class called ViewController with code
-(void)doLogin
{
self.service = [[SyncCommunicationService alloc]init];
NSData *data = [self.service sendSynchronousRequest:strNewLoginRequest
returningResponse:&response
error:nil];
}
I have tried calling this method in background and on main thread but still delegate methods are not getting called, I have tried many other answers from same website but still couldn't able to solve this issue so please can anybody have a clue what am I doing wrong.
I'm wondering why would anyone use asynchronous request for performing task synchronously? Not to mention this strange way to wait with while statement instead of dispatch_semaphore or something similar.
However, why You even bother with delegate? Just use class method sendSynchronousRequest:returningResponse:error:. I think, it would suffice in your case

how to send async http post - ios

I have a little problem with my app. I want to send some http request asynchronously to server. I create this method:
- (void)sendHTTPRequest:(NSString *)urlString type:(NSString *)type idNegozio:(NSNumber *)idNegozio {
self.negozi = [[NSMutableArray alloc] init];
NSData *jsonData;
NSString *jsonString;
if ([type isEqualToString:#"shops"]) {
self.reqNeg = YES;
self.reqApp = NO;
...
jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:0 error:nil];
jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
else if ([type isEqualToString:#"appointments"])
{
[self.loadingIconApp startAnimating];
self.reqNeg = NO;
self.reqApp = YES;
...
jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:0 error:nil];
jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
NSString *requestString = [NSString stringWithFormat:urlString];
NSURL *url = [NSURL URLWithString:requestString];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody: jsonData];
NSURLConnection * conn = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
[conn start];
}
and I use this methods for connection:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
self.responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (self.reqNeg == YES) {
//here use the responseData for my first http request
}
if (self.reqApp == YES) {
//here use the responseData for second http request
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
}
but in this way only the first connection works and I can use the responseData. While, If I try to send other http request the method connectionDidFinishLoading doesn't work and other methods too.
Anyone have an idea??
If you want to use the async request one by one you can do that:
- (void)request1 {
NSString *requestString = #"your url here";
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:[[NSURLRequest alloc]initWithURL:[NSURL URLWithString: requestString]]
queue:queue
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (!error && httpResponse.statusCode >= 200 && httpResponse.statusCode <300) {
// call the request2 here which is similar to request 1
// your request2 method here
}
}];
}
hope this help you~ thank you~
Your code looks good to me. Here are my ideas:
Are you sure your second NSURLConnection is being created and sent out?
Maybe it's never being sent.
Are you calling your sendHTTPRequest:type:idNegozio: method with a different type while your second connection is still sent out?
You don't have a check at the beginning of the send function to make sure you're not already sending out a connection. Maybe your flags are being switched mid-connection.
The if statements in your didFinish method should probably be combined with an else. Just in case you wanted to fire off an 'app' connection after handling a 'neg' connection you don't accidentally fall through and try to handle the response twice.
Also, you don't have to explicitly call 'start' on an NSURLConnection unless you pass NO to the startImmediately: parameter in the constructor. That shouldn't cause a problem though.

Set progress bar for downloading NSData

NSURL *url = [NSURL URLWithString:#"http://i0.kym-cdn.com/entries/icons/original/000/005/545/OpoQQ.jpg?1302279173"];
NSData *data = [NSData dataWithContentsOfURL:url];
imageView.image = [[[UIImage imageWithData:data];
I want to set progress bar while downloading.
To give a more detailed example:
in your .h file do
#interface YourClass : YourSuperclass<NSURLConnectionDataDelegate>
in your .m file do
#property (nonatomic) NSMutableData *imageData;
#property (nonatomic) NSUInteger totalBytes;
#property (nonatomic) NSUInteger receivedBytes;
And somewhere call
NSURL *url = [NSURL URLWithString:#"http://i0.kym-cdn.com/entries/icons/original/000/005/545/OpoQQ.jpg?1302279173"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
And also implement the delegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) urlResponse;
NSDictionary *dict = httpResponse.allHeaderFields;
NSString *lengthString = [dict valueForKey:#"Content-Length"];
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
NSNumber *length = [formatter numberFromString:lengthString];
self.totalBytes = length.unsignedIntegerValue;
self.imageData = [[NSMutableData alloc] initWithCapacity:self.totalBytes];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.imageData appendData:data];
self.receivedBytes += data.length;
// Actual progress is self.receivedBytes / self.totalBytes
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
imageView.image = [UIImage imageWithData:self.imageData];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//handle error
}
You can't get progress call backs by using that method.
You need to use an NSURLConnection and NSURLConnectionDataDelegate.
The NSURLConnection then runs asynchronously and will send callbacks to its delegate.
The main ones to look at are...
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
and
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
These are all used for getting the connection to do what you're already doing.
EDIT
Actually, see Marc's answer below. It is correct.
You can use MBProgress Hud class for loading view. You can download only two classes from here :-https://github.com/jdg/MBProgressHUD
After you write this code in that class which you want to load the data
Example :In your viewDidLoad you write this
- (void) viewDidLoad
{
MBProgressHud *spinner = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
spinner.mode = MBProgressHUDModeCustomView;
[spinner setLabelText:#"Loading....."];
[spinner setLabelFont:[UIFont systemFontOfSize:15]];
[spinner show:YES];
  [self performSelectorInBackground:#selector(getData) withObject:nil];
}
- (void) getData
{
NSURL *url = [NSURL URLWithString:#"http://i0.kym-cdn.com/entries/icons/original/000/005/545/OpoQQ.jpg?1302279173"];
NSData *data = [NSData dataWithContentsOfURL:url];
imageView.image = [[[UIImage imageWithData:data];
[spinner hide:YES];
[spinner removeFromSuperViewOnHide];
}

How to display web json data on uitableview on button click

i am using singleton class for web service calling and display in uitableview ,My function is when i clicked submit button of new orchardname for new add then view redirect to tableview but data not seen which add recently. "singOrchard.orcharsList" it's orchard name array which i have to display. "[wOrchrad getorchardslist]" it's my web service call.
- (IBAction)Submit:(id)sender
{
if (Orchadname.text.length == 0) {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"DataTree" message:#"Please Enter OrchardName" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[message show];
}
else {
[singOrchard.orcharsList removeAllObjects];
NSString *urlStr = [NSString stringWithFormat:#"http://xyz.com"]; // Passing token to URL
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:req delegate:self]; // Support to perform URLrequest
if (theConnection) { // checking connection successfull or not
webData1 = [NSMutableData data];
NSLog(#"Orchard Name is %#", Orchadname.text);
}
[wOrchrad getorchardslist];
NSLog(#"ARRAY COUNT %#",singOrchard.orcharsList);
[self performSelector:#selector(gotodetails) withObject:nil afterDelay:4];
}
}
"[wOrchard getorchardslist]- Singletone+Webserviceutility"
- (void)getorchardslist
{
orchardsnames = [[NSMutableArray alloc] init];
singltoneclass = [SingletoneClass sharedInstanceMethod];
theRequest =[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.xyz.com"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
webData = [NSMutableData data];
[theConnection start];
}
You are not using the return result from theConnection. (At least not in your provided code.) Since you have set your class as the delegate, implement the NSURLConnectionDataDelegate methods.
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
use it to save your JSON data to an NSArray, which you can then use in your UITableView.
If you send your request asynchrounsly, don't forget to append the data with
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

Cannot get data using NSURLConnection with GCD

So I am downloading some data from a server to my ios client. The data needs to be formatted so I use NSNotification to notify the app when the data has been downloaded completely and when thats done, I format the data and then display it on the screen.
All this is cool but because of the size of the data, the screen freezes.I thought I should use GCD to push the data downloading to another thread so the UI is still responsive. When i did that, I dont seem to be downloading any data.
I have a method getTops that uses NSURLConnection to download the data. Initially, in my viewDidLoad I called this method and it worked fine but then I used GCD like so
dispatch_queue_t getItemsQ = dispatch_queue_create("get Items", NULL);
dispatch_async(getItemsQ, ^{
[self getTops];
});
And it stopped working. I know it gets to the getTops because I can see the log in the console but it never reaches the -(void)connectionDidFinishLoading:(NSURLConnection *)connection
Here is the code i used:
-(void)getTops{
Keychain *keychain = [[Keychain alloc]init];
NSString *auth_token = [keychain getAuthToken];
NSLog(#"at getTops");
topimageArray = [[NSMutableArray alloc]init];
NSURLConnection *connection;
webData = [[NSMutableData alloc]init];
NSURL *url = [[NSURL alloc]initWithString:base];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]init];
[request setURL: url];
[request setValue:auth_token forHTTPHeaderField:#"X-AUTH-TOKEN"];
connection = [NSURLConnection connectionWithRequest:request delegate:self];
// [connection start];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSLog(#"at getTops conn start");
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(#"recieved response");
[webData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
if(data) {
NSLog(#"Appending data");
[webData appendData:data];
}
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSArray *response= [NSJSONSerialization JSONObjectWithData:webData options:0 error:nil];
NSLog(#"Tops full response::: %#",response);
theArray = [[NSArray alloc]initWithArray:response];
NSLog(#"DONE");
//Notify that the data is ready to be formated
[[NSNotificationCenter defaultCenter]postNotificationName:#"getTops" object:nil];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"error::::%#", error);
NSString *errormsg = error.localizedDescription;
UIAlertView *alertview = [[UIAlertView alloc]initWithTitle:#"Error" message:errormsg delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertview show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
I thought maybe I should remove the [UIApplication sharedApplication].networkActivityIndicatorVisible but that didnt help
Edit:: Added NSLogs to delegate methods.
The Log that I get is
at getTops conn start
And thats it.
The simplest way is to use sendAsynchronousRequest:queue:completionHandler:. No delegates are necessary, just put the code from connectionDidFinishLoading: in the completion block.
Loads the data for a URL request and executes a handler block on an operation queue when the request completes or fails.
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
< your code >
}];

Resources