Objective-C: HTTP requesting (POST/GET) and JSON parsing

Screen Shot 2017-04-22 at 00.35.00

Swift is growing fast and become beautiful programming language, but it is too early to forget about Objective-C. The main reason is that corporate world is still developing iOS apps using this older language.

So I decided to write little series of posts with Objective-C code examples. Let’s start from the feature that is used almost in every mobile app: HTTP requesting. We will make GET request to get forecast in Prague and parse JSON response.

Step 1.

Create “Single View Application”. Don’t forget to set right language.

Screen Shot 2017-04-19 at 19.11.50

Step 2.

As discussed in this post (Step 2) generate OpenWeatherMap API key.

Step 3.

Let’s “draw” elements. I’d like to do it purely using code.

UILabel *valueLabel;

- (void)viewDidLoad {
    [super viewDidLoad];
    [self buildView];
}

- (void) buildView {
    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
    
    UIView *celsiusView = [[UIView alloc] initWithFrame:CGRectMake(
                                                                   0,
                                                                   0,
                                                                   screenWidth,
                                                                   200)];
    celsiusView.layer.borderColor = [UIColor grayColor].CGColor;
    celsiusView.layer.borderWidth = 1.0f;
    [self.view addSubview:celsiusView];
    
    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(
                                                                    30,
                                                                    30,
                                                                    celsiusView.frame.size.width - 60,
                                                                    20)];
    titleLabel.text = @"Weather in Prague";
    titleLabel.textAlignment = NSTextAlignmentCenter;
    [celsiusView addSubview:titleLabel];
    
    valueLabel = [[UILabel alloc] initWithFrame:CGRectMake(
                                                           30,
                                                           titleLabel.frame.origin.y + titleLabel.frame.size.height + 10,
                                                           celsiusView.frame.size.width - 60,
                                                           20)];
    valueLabel.text = @"---";
    valueLabel.textAlignment = NSTextAlignmentCenter;
    [celsiusView addSubview:valueLabel];
    
    UIButton *updateButton = [[UIButton alloc] initWithFrame:CGRectMake(
                                                                        (screenWidth - 200)/2,
                                                                        valueLabel.frame.origin.y + valueLabel.frame.size.height + 20,
                                                                        200,
                                                                        30)];
    [updateButton setTitle:@"Update" forState:UIControlStateNormal];
    updateButton.showsTouchWhenHighlighted = true;
    updateButton.backgroundColor = [UIColor grayColor];
    [updateButton addTarget:self action:@selector(updateWeather:) forControlEvents:UIControlEventTouchUpInside];
    [celsiusView addSubview:updateButton];
    
    
}

So you should have this view:

Screen Shot 2017-04-19 at 21.45.56

Step 4.

Don’t forget to add “App Transport Security Settings” with element “Allow Arbitrary Loads” => “YES“ in info.plist, because we are going to making non-secure request (connecting to API without https).

Step 5.

It’s time to write the logic. Code snippet:

- (void) updateWeather:(UIButton *) sender {
    
    //NSString *post = @"postKey=postVar";
    //NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
    
    //NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:@"http://api.openweathermap.org/data/2.5/weather?q=Praque&units=metric&APPID={YOUR_API_KEY}"]];
    [request setHTTPMethod:@"GET"];
    //[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    //[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    //[request setHTTPBody:postData];

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:
                                  ^(NSData *data, NSURLResponse *response, NSError *error) {
                                      if (data == nil) {
                                          [self printCannotLoad];
                                      } else {
                                          [self parseWeatherJSON:data];
                                      }
                                  }];
    [task resume];

}

- (void) parseWeatherJSON:(NSData *) jsonData {
    NSError *error = nil;
    id object = [NSJSONSerialization
                 JSONObjectWithData:jsonData
                 options:0
                 error:&error];
        
    if(error) {
        [self printCannotLoad];
        return;
    }
        
    if ([object isKindOfClass:[NSDictionary class]]) {
        NSDictionary *mainObject = [object valueForKey:@"main"];
        NSDictionary *weatherObject = [object valueForKey:@"weather"][0];
        NSString *textString = [NSString stringWithFormat:@"%@, %@ celsius", weatherObject[@"description"], mainObject[@"temp"]];
        dispatch_sync(dispatch_get_main_queue(), ^{
            valueLabel.text = textString;
        });
    } else {
    }
}

- (void) printCannotLoad {
    dispatch_sync(dispatch_get_main_queue(), ^{
        valueLabel.text = @"cannot load";
    });
}

In updateWeather function we are making HTTP request using GET method. GET keys and values written in URL. In case of success getting response from the URL, we run parseWeatherJSON. Otherwise show error message (printCannotLoad function). In commented lines you can see example of POST request. Please pay attention that most of examples in internet show old method of making request using NSURLConnection.

In parseWeatherJSON we took out “main” and “weather” objects from core object. Pay attention to make any change in view in main thread. In parseWeatherJSON code is running in background thread because it run by completionHandler.

Step 6.

Now you can discover weather in Prague at any time :)

Screen Shot 2017-04-22 at 00.35.00

You can find this project in my GitHub account.

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Profile photo of Doszhan Kalibek

Doszhan Kalibek

  • Риект Риект

    cannot load (((
    some problems with downloading json from http