NSURLSession and API - objective-c

I am extremely confused with the NSUrlSession and the API. This is my first time trying to use an API so please explain this in the simplest form possible.
I found an API which gets the weather, I have made a string for the weather location. then did all the NSUrl / nsurlrequest. My goal is to output everything so I can see the keys of that API. Heres what I have so far but all It displays is 'Program ended with exit code 0'
I don't really know what is happening during the NSUrlsession because I learned how to use API with the NSUrlConnection via a youtube video.
NSString *location = #"London";
NSString *weatherString = [NSString stringWithFormat:#"https://api.openweathermap.org/data/2.5/weather?q=%#", location];
NSURL *weatherURL = [NSURL URLWithString:weatherString];
NSURLRequest *request = [NSURLRequest requestWithURL:weatherURL];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error){
NSDictionary *weatherDictionary = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:nil];
NSLog(#"%#", [weatherDictionary description]);
}];

It's hard to tell from this snippet, but one or more of the following problems are likely causing your issues:
You are retaining a reference to that task somewhere, right?
From the documentation for dataTaskWithRequest, you need to call [task resume] to actually start the task.
That URL won't work, because the api.openweathermap.org site doesn't support HTTPS. You'll need to change it to http, and possibly add an exception in the app's Info.plist to allow non-secure connections (they're disabled by default for new apps).
After you fix all that, you'll need an API key for the request to actually succeed.

Related

Request NSURLSession with SSL .cert and .key files

I have to login via https in an Obj-C project. Everything is fine with all the url, the user, pass and the needed stuff. For identify, the server checks by ssl .cert and .key files. So far, so good, the files were uploaded to the server, and the connection made well by curl from terminal.
Here comes my problem.
Spend some days, read the available stuff here and there, but simply can't find any solution to send the ssl files with the request in Obj-C. (The server cannot accept p12)
Here's the curl:
curl -q -k --cert cert2048.crt --key key2048.key https://somesite.com/ -d "username=usrnm&password=psswrd"
Here's my Obj-C code so far:
-(void)connect {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://somesite.com/"]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSDictionary* bodyParameters = #{
#"username": #"usrnm",
#"password": #"psswrd"
};
[request setHTTPBody:[self httpBodyForParameters:bodyParameters]];
[request setHTTPMethod:#"POST"];
[request setValue:#"gzip, deflate" forHTTPHeaderField:#"Accept-Encoding"];
[request setValue:#"keep-alive" forHTTPHeaderField:#"Connection"];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSError *jsonError;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
NSLog(#"%#", jsonResponse);
}];
[postDataTask resume];
}
(httpBodyForParameters simply sets up the request body)
The connection establish, everything passes, the jsonResponse holds response as expected (well, the error message about authentication failure, in regular format). But I simply can't find a way to send the ssl files as in the curl line. Sadly, https authentication is far beyond my knowledge. I'm stucked. Every help appreciated.
Thank you,
Sz
That curl command is using the cert and key as a client certificate for authentication, not sending them as files. It's actually part of the authentication handshake.
The code for importing PKCS data and using it in response to a client certificate challenge is fairly involved, so rather than try to explain it all off the top of my head, I'm going to point you to another Stack Overflow question and answer that contain pretty extensive code snippets.
Creating a SecCertificateRef for NSURLConnection Authentication Challenge
However, be aware that some of the code in that link is not quite correct. For the protection spaces that are not handled, you should use default handling, not cancel the challenge.

Running app in Debug via Xcode vs running app manually

I have a Cocoa application. It runs fine via XCode 6, but when I run it manually via Finder, it behaves very strange: it seems that only the static XIB loads, no other code gets executed.
Do I need to sign it in order to work? I also tried archiving. For any clues, this is the code that executes first:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:verb];
NSData *data = [qs dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:data];
NSError *err;
NSURLResponse *response;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSString *resSrt = [NSString stringWithFormat:#"%#", responseData];
Yes, there are HTTP requests made first in applicationDidFinishLaunching for the design to change.
Thank you!
EDIT: Forgot to mention that I use dispatch_queue_t and dispatch_async for those requests, so I am not blocking the main thread.
I was actually having problems with some inexistent files.

How to upload to ASP.NET in Objective-C using NSURLSession

I need to upload an image to my ASP.Net website, i have got it to work with NSURLConnection but when i needed to upload extremely big files, it crashes due to the lack of ram to transfer the file to NSData then upload it. So I found out about the new API NSURLSession and the method uploadTaskWithRequest:withFile to allow bigger files to be transferred. I have changed the max file limit on the ASP.NET server to allow huge files, and tested it and it works with large files (100MB+), but at some point the phone does not have enough ram to allocate the NSData of the file, when I use NSURLConnection. I have tried NSURLSession numerous times with no success.
Heres an example of what i've tried:
NSString *urlString = [NSString stringWithFormat:#"https://examplesecuresite.com/Index.aspx?username=%#", username];
NSMutableURLRequest *request =
[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"PUT"];
// 3
NSData *noteContents = UIImageJPEGRepresentation(image, 1);
// 4
NSURLSession *session = [[NSURLSession alloc] init];
NSURLSessionUploadTask *uploadTask = [session
uploadTaskWithRequest:request
fromData:noteContents];
[uploadTask resume];
A couple of reactions:
This is not how you create a NSURLSession. You should either use the shared session:
NSURLSession *session = [NSURLSession sharedSession];
Or create a configuration with a delegate (obviously, implementing the NSURLSessionTaskDelegate and NSURLSessionDelegate protocols) and use that:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
fromData:noteContents];
Or create a configuration without a delegate (but create upload task with completion block) and use that:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:noteContents completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"%#", error);
return;
}
// do whatever other checking you want of the response here
}];
I don't know why you're retrieving the NSData from the UIImage. If this is a UIImage that you created dynamically (e.g. a screen snapshot), then fine, that's what you have to do. But if you can go back to the original asset (e.g. the original asset from ALAssetLibrary, the file we used in imageWithContentsOfFile or imageWithContentsOfURL, etc.), often that will be more efficient (both smaller asset as well as you can upload directly from persistent storage).
Unfortunately, using UIImageJPEGRepresentation with a quality setting of 1.0 often retrieves a much larger NSData than the original asset. (Plus we preserve any meta data, if any, its far more memory efficient, etc.) You can use a factor of 0.9 or 0.8, which is lossy, but will result in a much smaller file. If you really want something lossless, often UIImagePNGRepresentation will generate a smaller file than UIImageJPEGRepresentation with a quality setting of 1.0.
If you're worried about a memory efficient approach, this seems no more efficient. You're uploading a NSData in RAM. Any approach that consists of loading the data into a NSData will be no more memory efficient than your other approach, most likely.
If you want to be more memory efficient, avoid loading the image into an NSData at all (if you can), and just use the uploadTaskWithRequest:fromFile: with the original asset.
By the way, if you had the image in a file in persistent storage, it doesn't strike me that you have to make the shift to NSURLSession solely to address the memory issues. Strikes me that you could have use the delegate-based NSURLConnection, returning a NSInputStream from connection:needNewBodyStream: rather than loading the image into a NSData.

Loading a website without opening it in Safari

would like to be able to load a website without loading it in Safari (for server call purposes)
I tried theses two methods but they don t work at all :
NSString *connected = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://www.google.com"] encoding:NSStringEncodingConversionAllowLossy error:nil];
and
NSURL *URL = [NSURL URLWithString:#"http://www.google.com"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:URL];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error];
but both these options don t load the website unfortunatley , any reasons ?
If you are trying to display the webpage, you should check out the UIWebView class or WebView class on OS X.
You may find the following sample code to be useful, PrintWebView (OS X), UICatalog (iOS).
If you are trying to download the HTML source of the webpage, then you really don't want to be using stringWithContentsOfURL:. It will block the main thread, for more information see Synchronous Networking on the Main Thread.

iOS Programming with Web database interface

I am programming in Obj-C with X-code and I want to create a project where I am able to pull up information from the database that I have created in my website.
I understand that this can be safely and easily done with a mobile web application. Any ideas how on how I parse the database with Objective-C and X-code ?
Please reply.
Thanks and regards,
-Venkat
If i'm not mistaken the iOS SDK can not connect directly to your database. The way I do this is to send out a post request using the ASIHTTP class and then parse the returned data from your website. Read the documentation here.
This is an example of how to use it from one of my own applications:
NSURL *url = [NSURL URLWithString:#"yoursite.com/page.php"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:variable1 forKey:#"key1"];
[request setPostValue:variable2 forKey:#"key2"];
[request setPostValue:variable3 forKey:#"key3"];
[request setDelegate:self];
[request startAsynchronous];
You then catch the result with the following code:
- (void)requestFinished:(ASIHTTPRequest *)request {
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
//do your parsing here
}
}
Don't forget to include the required files and classes to your app. But it's all explained in the documentation.
Hope it helps a bit!