1

I am currently trying to get weather information from a URL and into a string or data file that I can use to display the information on screen using labels.

I have edited the following based on the responses I have gotten so far; the code I have so far is as follows:

// Method 1
NSString *path = @"http://api.openweathermap.org/data/2.5/weather?q={London}&appid=4737e39e801a13bd10da52d8837e470b";
NSURL *url = [NSURL URLWithString:path];
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error = nil;
NSDictionary *s = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; // This line triggers the exception error

// method 2
NSString *path = @"http://api.openweathermap.org/data/2.5/weather?q={London}&appid=4737e39e801a13bd10da52d8837e470b";
NSURL *url = [NSURL URLWithString:path];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
NSDictionary *s = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]; // this line triggers the exception error


// Method 3
NSString *path = @"http://api.openweathermap.org/data/2.5/weather?q={London}&appid=4737e39e801a13bd10da52d8837e470b";
NSURL *url = [NSURL URLWithString:path];
NSError *error = nil;
NSMutableArray *array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error]; // this line triggers exception error
/*
if (error)
    NSLog(@"JSONObjectWithData error: %@", error);

for (NSMutableDictionary *dictionary in array)
{
    NSString *arrayString = dictionary[@"array"];
    if (arrayString)
    {
        NSData *data = [arrayString dataUsingEncoding:NSUTF8StringEncoding];
        NSError *error = nil;
        dictionary[@"array"] = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
        if (error)
            NSLog(@"JSONObjectWithData for array error: %@", error);
    }
}
 */

 // Method 4
 //-- Make URL request with server
 NSHTTPURLResponse *response = nil;
 NSString *jsonUrlString = [NSString stringWithFormat:@"http://api.openweathermap.org/data/2.5/weather?q={London}&appid=4737e39e801a13bd10da52d8837e470b"];
 NSURL *url = [NSURL URLWithString:[jsonUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

 //-- Get request and response though URL
 NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
 NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];

 //-- JSON Parsing
 NSMutableArray *result = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil]; // This line triggers the exception error
 //NSLog(@"Result = %@",result);

I've commented out or separated parts because I am getting an exception handler error, and I narrowed it down to this line (or the equivalent in different methods):

NSMutableDictionary *s = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];

It may have something to do with the JSON data, the format, the source, or maybe I need to change settings or permissions before accessing it. I did get this message with method 4: "pp Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file." But I do not know what edits I need to make, and it says temporary, so I assume that's not how you're meant to fix it anyway. I do not even know if this is related to my issue, or something else I will have to face.

JSON data in question looks like following:

{
    "coord":{"lon":-0.13,"lat":51.51},
    "weather":[{"id":801,"main":"Clouds","description":"few clouds","icon":"02d"}],
    "base":"stations",
    "main":
        {"temp":282.4,"pressure":1014,"humidity":76,"temp_min":281.15,"temp_max":284.15},
    "visibility":10000,
    "wind":{"speed":4.1,"deg":280},
    "clouds":{"all":20},
    "dt":1486471800,
    "sys":
        {"type":1,"id":5091,"message":0.004,"country":"GB","sunrise":1486452468,"sunset":1486486938},
    "id":2643743,
    "name":"London",
    "cod":200
}

And ultimately I want to be able to access it with something like:

NSString *temperature =s[@"temperature"];
NSLog(@"%@", temperature);
NSString *humidity = [s objectForKey:@"humidity"]; 

Any further assistance would be greatly appreciated; Thanks in advance and to those that have guided me already :)

  • Welcome to SO. You should search for answers before creating your own. This has been asked **many** times and there are many answers to the same issue that all are basically the same. –  Feb 09 '17 at 02:05
  • Thank you; over the last couple of weeks, i have found that after the latest updates, many of the older posts regarding my queries don't work anymore, so far, none of the answers in that link have worked, and since I don't know which is the actual problem, I've posted what I've done and specified the platform, in hopes to find the issue. It might be the JSON data format from the website, which is different to the examples in that link, it might be security or settings which isn't mentioned in the link so I wouldn't know from that if mine are right, and it might be something else – Daniel No Kuroikaze Feb 10 '17 at 00:28
  • I removed the duplicate flag. However, it is helpful for the rest if you write in your question that you have searched through similiar questions already and link some, and that they did not work for you. Your problem here is the **"Transport Security has blocked a cleartext HTTP"** You can not connect to insecure servers from iOS anymore. You need to either run https or add the key and URL to your plist. **Check here for the answer**: http://stackoverflow.com/questions/30731785/how-do-i-load-an-http-url-with-app-transport-security-enabled-in-ios-9 Apple may reject your app without https –  Feb 10 '17 at 11:29

4 Answers4

3

Change this code:

NSData *data = [[NSData alloc] initWithContentsOfFile:path];
NSMutableDictionary *s = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];

into this:

NSData *data = [NSData dataWithContentsOfURL:path];
NSError *error = nil;
NSDictionary *s = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];

UPDATE

You are still getting error is because of these 2 lines:

NSString *path = @"http://api.openweathermap.org/data/2.5/weather?q={London}&appid=4737e39e801a13bd10da52d8837e470b";
NSURL *url = [NSURL URLWithString:path];

Your url is nil because your path contains special characters. Change those 2 lines into these:

NSString *path = [@"http://api.openweathermap.org/data/2.5/weather?q={London}&appid=4737e39e801a13bd10da52d8837e470b" stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *url = [NSURL URLWithString:path];
The Mach System
  • 6,703
  • 3
  • 16
  • 20
  • Thank you for the help, but I am still getting the "uncaught exception" error even with these modifications, are there any steps in my code that are missing, anything you can think of since this is new territory to me and I might have missed something otherwise obvious – Daniel No Kuroikaze Feb 09 '17 at 23:28
  • Please check out my updated answer. This will solve your problem. – The Mach System Mar 09 '17 at 00:38
2

Most likely data is nil. The one thing JSONObjectWithData considers a programming error is being passed nil; that's when it throws an exception. I don't think initWithContentsOfFile accepts URLs that are not file URLs.

BTW. The result is most definitely not an NSMutableDictionary. It may be an NSDictionary, but you need to check this. And instead of [s objectForKey:@"temperature"] just write s[@"temperature"].

gnasher729
  • 51,477
  • 5
  • 75
  • 98
0

You have three problems:

  1. you are trying to open a remote data source as a file
  2. a remote data source string must be converted to a URL
  3. the return type from NSJSONSerialization is just an NSDictionary

Here is the corrected code:

NSString *path = @"http://api.openweathermap.org/data/2.5/weather?q={London}&appid=4737e39e801a13bd10da52d8837e470b";
NSURL *url = [NSURL URLWithString:path];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
NSDictionary *s = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
Chris Edgington
  • 1,208
  • 12
  • 11
  • Thank you for the advice, I tried this method and while my debugging got further, I am still getting an "uncaught exception of type NSException" error on the line: - NSDictionary *s = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]; - Any idea why that might be happening, or if I am missing something else? The url definitely works (you can test in your own browser) – Daniel No Kuroikaze Feb 09 '17 at 23:23
  • You'll need to add some NSLog statements related to the NSData object returned from initWithContentsOfURL. Check that for nil, if its non-nil, dump the contents, etc. – Chris Edgington Feb 10 '17 at 16:42
0

Did you manage to disable ATS? Try to add the following to you Info.plist:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <true/>
</dict>

I would also add a check for data:

NSString *path = @"http://api.openweathermap.org/data/2.5/weather?q={London}&appid=4737e39e801a13bd10da52d8837e470b";
NSURL *url = [NSURL URLWithString:path];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
NSAssert(data, @"No data received!");
NSDictionary *s = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];