1

I'm starter in Objective - C, I have a method

- (void)getAltitudeFromElevationFromAlt:(float)latitude Long:(float)longitude{
    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSString *apiKey = @"IzaSyA5CDPUYC7GY5PzJdu_K4ouRy55gm3R5BO4";
        NSString *address = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/elevation/json?locations=%f,%f&key=%@", latitude, longitude, apiKey];
        // Send a synchronous request

        NSURLRequest * urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:address]];
        NSURLResponse * response = nil;
        NSError * error = nil;
        NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest
                                              returningResponse:&response
                                                          error:&error];

       NSString *str = @"No Data";
        if (error == nil)
        {
            NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
            str = [NSString stringWithFormat:@"%@", dictionary[@"results"][0][@"elevation"]];
            //  NSLog(@"text  = %@", dictionary[@"results"][0][@"elevation"]);
            NSLog(@"str = %@", str);
            dispatch_async( dispatch_get_main_queue(), ^{
                _altitudeMeterLabel.text = str;
            });
        }
    });
}

please help to change this sequence

NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest
                                          returningResponse:&response
                                                      error:&error];
Rob
  • 415,655
  • 72
  • 787
  • 1,044

4 Answers4

2

Use NSURLSession and an asynchronous request:

- (void)getAltitudeFromElevationFromAlt:(float)latitude Long:(float)longitude {

   NSString *apiKey = @"IzaSyA5CDPUYC7GY5PzJdu_K4ouRy55gm3R5BO4";
   NSString *address = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/elevation/json?locations=%f,%f&key=%@", latitude, longitude, apiKey];
   // Send an ASYNCHRONOUS request

   NSURLRequest * urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:address]];
   [[[NSURLSession sharedSession] dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
      NSString *str = @"No Data";
      if (error) {
         NSLog(@"%@", error);
      } else {
         NSError * jsonError = nil;
         NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];
         if (jsonError) {
            NSLog(@"%@", jsonError);
         } else {
            str = [NSString stringWithFormat:@"%@", dictionary[@"results"][0][@"elevation"]];
            //  NSLog(@"text  = %@", dictionary[@"results"][0][@"elevation"]);
            NSLog(@"str = %@", str);
         }
         dispatch_async( dispatch_get_main_queue(), ^{
            _altitudeMeterLabel.text = str;
         });
      }
   }] resume];
}

Note:

The global dispatch_async block is not needed since the data task is dispatched to a background thread anyway.

vadian
  • 274,689
  • 30
  • 353
  • 361
0

Use NSURLSession with dataTaskWithRequest

- (void)getAltitudeFromElevationFromAlt:(float)latitude Long:(float)longitude
{
    NSString *apiKey = @"IzaSyA5CDPUYC7GY5PzJdu_K4ouRy55gm3R5BO4";
    NSString *address = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/elevation/json?locations=%f,%f&key=%@", latitude, longitude, apiKey];

    NSURLRequest * request = [NSURLRequest requestWithURL:[NSURL URLWithString:address]];
    NSURLResponse * response = nil;
    NSString *str = @"No Data";

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                         completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error) {
    if (error == nil)
    {
        NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
        str = [NSString stringWithFormat:@"%@", dictionary[@"results"][0][@"elevation"]];
        //  NSLog(@"text  = %@", dictionary[@"results"][0][@"elevation"]);
        NSLog(@"str = %@", str);
        dispatch_async( dispatch_get_main_queue(), ^{
            _altitudeMeterLabel.text = str;
        });
    }
    }];

     [task resume];    
}     
Shrikant Tanwade
  • 1,391
  • 12
  • 21
  • Yep, use `dataTaskWithRequest`. But you still have `sendSynchronousRequest` in there, too! All of that code should be removed. Also, the dispatch to the global queue is not needed. – Rob Nov 15 '16 at 09:29
0

Please try Following Code

    - (void)getAltitudeFromElevationFromAlt:(float)latitude Long:(float)longitude{
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSString *apiKey = @"IzaSyA5CDPUYC7GY5PzJdu_K4ouRy55gm3R5BO4";
    NSString *address = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/elevation/json?locations=%f,%f&key=%@", latitude, longitude, apiKey];
   // Send a synchronous request

    NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithURL:[NSURL URLWithString:address]
            completionHandler:^(NSData *data,
                                NSURLResponse *response,
                                NSError *error) {
                NSString *str = @"No Data";
                if (error == nil)
                {
                    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
                    str = [NSString stringWithFormat:@"%@", dictionary[@"results"][0][@"elevation"]];
                    //  NSLog(@"text  = %@", dictionary[@"results"][0][@"elevation"]);
                    NSLog(@"str = %@", str);
                    dispatch_async( dispatch_get_main_queue(), ^{
                        _altitudeMeterLabel.text = str;
                    });
                }

            }] resume];
    });

}

Yog
  • 1
  • Yep, this is largely right, though the outer dispatch to the global queue is no longer needed. – Rob Nov 15 '16 at 09:31
0

Synchronous methods are deprecated from iOS 9, because it block the main thread for that time. So its not advisable to do send execute this operation synchronously.

If really needed you can create category of NSUrlSession to execute your request synchronously.

#import "NSURLSession+Sync.h"

@implementation NSURLSession (Sync)

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request
                 returningResponse:(__autoreleasing NSURLResponse **)responsePtr
                             error:(__autoreleasing NSError **)errorPtr {
    dispatch_semaphore_t    sem;
    __block NSData *        result;

    result = nil;

    sem = dispatch_semaphore_create(0);

    [[[NSURLSession sharedSession] dataTaskWithRequest:request
                                     completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                         if (errorPtr != NULL) {
                                             *errorPtr = error;
                                         }
                                         if (responsePtr != NULL) {
                                             *responsePtr = response;
                                         }  
                                         if (error == nil) {  
                                             result = data;  
                                         }  
                                         dispatch_semaphore_signal(sem);  
                                     }] resume];  

    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);  

    return result;  
}
@end

and use in code like following:

  NSData * data = [NSURLSession sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
PlusInfosys
  • 3,416
  • 1
  • 19
  • 33
  • Semaphores are bad programming habit, because they block the thread, too. There is no need at all to perform this kind of task synchronously. – vadian Nov 15 '16 at 09:26
  • @iOS_devloper - He was dispatching this to a global queue (so that the blocking synchronous request wouldn't block the main thread, presumably). Rather than taking an asynchronous method, using a semaphore to make it synchronous, and then dispatching it to a global queue to make it asynchronous again, he should just do standard asynchronous pattern and be done with it. – Rob Nov 15 '16 at 09:26
  • Agree, and thats why I stated, Its not advisable to do this kind of task synchronously. But if you need to do, this is way. – PlusInfosys Nov 15 '16 at 10:12