2

Hi i am beginner in ios and when ever we are calling services using NSURLRequest i want to know want to know what happening when we are calling services with "Synchronous request" and calling services with asynchronous request programmatically, Please explain that operations programmatically and i have written some code in below using that code explain Synchronous and asynchronous operations

my code:-

- (void)viewDidLoad {
    [super viewDidLoad];

 NSURL *url = [NSURL URLWithString:@"http://api.kivaws.org/v1/loans/search.json?status=fundraising"];
        NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];

        [theRequest setHTTPMethod:@"GET"];
        [theRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"];
        [theRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
        [theRequest setTimeoutInterval:5];

        NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

        if(connection){

            webData = [[NSMutableData alloc] init];
        }
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

    [webData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    [webData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {

    NSLog(@"error is %@",[error localizedDescription]);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    NSString * allDataDictionbary = [[NSString alloc] initWithData:webData encoding:NSUTF8StringEncoding];

    NSArray * responseString = [allDataDictionbary JSONValue];

   NSLog(@"final respone dictionary%@",responseString);
   }
AbhiRam
  • 2,033
  • 7
  • 41
  • 94
  • Re difference between synchronous requests and asynchronous requests, see http://stackoverflow.com/q/21122842/1271826. Regarding this code sample, this is an asynchronous request and that's good, because you don't want to be making synchronous requests from the main thread. In fact, synchronous network requests are such a bad idea that the new `NSURLSession`, which replaces the deprecated `NSURLConnection` you use in your code sample, doesn't even offer a synchronous rendition. – Rob Dec 12 '15 at 09:19
  • hi @Rob i am very beginner for Ios and your saying that don't use NSURLConnection at all any more. Use NSURLSession how can i use that please update my code – AbhiRam Dec 12 '15 at 09:31

4 Answers4

4

In answer to your question, synchronous requests block the thread from which they were called until the request finishes. (And for this reason, synchronous requests are generally discouraged.) Asynchronous requests let the current thread continue execution (e.g. continue to respond to user interaction with the app; respond to system events; etc.) while the request is being performed. This generally preferable.

Your code was performing asynchronous request (which is good). There were some issues, though:

  1. You shouldn't use NSURLConnection anymore. It's deprecated. Use NSURLSession. It's actually simpler, as you generally don't have to write those delegate methods (unless you want to because you have some compelling need to do so).

    For more information on NSURLSession, see the Using NSURLSession in the URL Session Programming Guide. Or see WWDC 2013 video What's New in Foundation Networking for a nice introduction.

  2. You aren't doing some error handling. You're checking for fundamental errors (e.g. no network), which is very good, but you weren't considering other web server errors which may not always result in a NSError object, but may simply result in a HTTP status code other than 200. I'd suggest checking for that.

    See section 10 of RFC 2616 for a list of HTTP status codes.

  3. You are setting a Content-Type of application/json. But this isn't a JSON request. (Sure, the response is JSON, but the request isn't.) Often you'd use application/x-www-form-urlencoded for requests like this.

  4. In your code snippet, you suggested that the response from the server was JSON with a NSArray as the top level object. But the top level object is a NSDictionary.

  5. You are using JSONValue. I'm not sure which JSON library that is, but many of us just use the built-in NSJSONSerialization class that Apple provides. A long time ago, before Apple provided NSJSONSerialization, we'd use third-party libraries for parsing JSON, but that's no longer needed.

The correct way to send a request with NSURLSession is as follows:

NSURL *url = [NSURL URLWithString:@"http://api.kivaws.org/v1/loans/search.json?status=fundraising"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

[request setHTTPMethod:@"GET"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (error != nil) {
        NSLog(@"fundamental network error = %@", error);
        return;
    }
    
    if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
        NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
        if (statusCode != 200) {
            NSLog(@"Warning; server should respond with 200 status code, but returned %ld", (long)statusCode);
        }
    }
    
    NSError *parseError;
    NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];
    if (responseObject) {
        NSLog(@"responseObject = %@", responseObject);
    } else {
        NSLog(@"Error parsing JSON: %@", parseError);
        NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"responseString = %@", responseString);
    }
}];
[task resume];

// Note, you'll reach this portion of your code before the
// above `completionHandler` runs because this request runs
// asynchronously. So put code that uses the network response
// above, inside that `completionHandler`, not here.
Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • because of why i have used there JSONValue in my application i have used third party library which is SBJSON libary – AbhiRam Dec 12 '15 at 10:04
  • and so many peoples also saying that using NSJSONSerialization is just for getting small data and for getting large amount of data better to use SBJSO N is it how much correct @Rob? – AbhiRam Dec 12 '15 at 10:06
  • That's fine, if you really want to use that, that's fine. I'm just pointing out that we no longer need to use those third party libraries for JSON parsing. But if you have a lot of code, dependent upon that library, feel free to continue to use it, if you must. Regarding the speed of the JSON parsing, this JSON certainly isn't large enough for there to be any material difference. I personally always minimize the presence of third-party code, limiting it to that which offers a significant benefit, which is not the case here, IMHO. – Rob Dec 12 '15 at 10:32
  • ok @Rob i have one small bought how can post data using NSURLSession suppose i am having data like (NSDictionary *mainDict = [NSDictionary dictionaryWithObjectsAndKeys: @"123" ,@"medicaId",@"something",@"password", nil];) – AbhiRam Dec 12 '15 at 10:32
  • i think i have to use POST method here but i don't know how to send data usinng NSUrlSEssion can you plase explain that – AbhiRam Dec 12 '15 at 10:34
  • You should search Stack Overflow of "NSURLSession POST", e.g. http://stackoverflow.com/questions/24250475/post-multipart-form-data-with-objective-c/24252378#24252378 or, perhaps better, http://stackoverflow.com/questions/25701436/how-to-make-post-nsurlrequest-with-2-parameters/25702239#25702239. The main trick (often overlooked) is to properly percent escape the request. All of this is assuming, of course, that your server is looking for "standard" `x-www-form-urlencoded` requests, as suggested by your snippet above... – Rob Dec 12 '15 at 10:35
  • hi @Rob just now i have seen your answer here http://stackoverflow.com/questions/25701436/how-to-make-post-nsurlrequest-with-2-parameters/25702239#25702239 and here you have used PercentageEscapedString method i am not understand what is the use of that can you please explain that clearly – AbhiRam Dec 12 '15 at 12:09
  • A `x-www-form-urlencoded` request essentially looks like `medicaid=123&password=something`. The `&` is what separates the parameters. So what if one of the values, themselves, included an ampersand?!? The purpose of percent escaping is to ensure that special "reserved" characters, like that, can be safely included within the value and not be misinterpreted by the web server. The `&` is just one example of this issue. All reserved characters should be percent escaped. See http://stackoverflow.com/a/20777164/1271826 – Rob Dec 12 '15 at 13:16
0

Synchronous request block the thread until it completes. while Asynchronous request creates separate thread and execute, on completion get back on main thread.

when you run this lines there is time diffrence of 1 sec or depends on net speed

 NSLog(@"before SynchronousRequest time %@",[NSDate date]);
    NSError *error = nil;
    NSHTTPURLResponse *response = nil;
    NSData *data=[NSURLConnection sendSynchronousRequest:request returningResponse:&response   error:&error];
    NSLog(@"after SynchronousRequest time %@",[NSDate date]);

before SynchronousRequest time 2015-12-12 09:26:01 +0000

after SynchronousRequest time 2015-12-12 09:26:02 +0000

when you run this lines there no time diffrence

 NSLog(@"before AsynchronousRequest time %@",[NSDate date]);
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        if (data) {
            NSString *str = [[NSString alloc] initWithData:data
                                                 encoding:NSUTF8StringEncoding];  // note the retain count here.
            NSLog(@"%@",str);
        } else {
            // handle error
        }
    }];
    NSLog(@"after AsynchronousRequest time %@",[NSDate date]);

before AsynchronousRequest time 2015-12-12 09:29:50 +0000

after AsynchronousRequest time 2015-12-12 09:29:50 +0000

Nitin Singh
  • 271
  • 2
  • 12
0

When an HTTP request is initiated from a thread, the thread can decided to take care of getting you your response all by itself, if you don't mind being patient ("thank you for waiting"). That thread is blocked until the HTTP request is fully transacted. Alternatively, the thread can think he has better things to do than wait around for a lengthy HTTP transaction, and so he happily passes off the task to another process to handle the HTTP transaction, along with a a callback so they can keep in touch. When the other process completes, it uses the call back to its initiator that it's done.

Justin Zealand
  • 196
  • 2
  • 7
0

Think of it as a road. Imagine your app will operate on only one road, if not told to do otherwise. Now, everything that happens in your app has to stay on that road. If any "car"(read: task) is taking too long, the entire thing shuts down and your "road"(read: app) becomes unresponsive. In an asynchronous operation, you create another road(read: thread) and the car that is going slowly can switch to that road. Once its fast enough to operate on the main road, it can switch back on it.

Sam Fischer
  • 1,442
  • 19
  • 35