2

I previously asked a similar question on this but didn't get much help and have now looked into it further and still can't see why I have a problem.

NSURL *url = [NSURL URLWithString:@"http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/sitelist?res=daily&key=<MY API KEY>"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
    NSLog(@"Success");
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
    NSLog(@"Fail");
}];
[operation start];

This fails with the following

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil'

I believe the problem is due to the JSON type returned as ISO-8859-1, I managed to get this working with NSJSONSerialization by encoding the retuned string to NSUTF8StringEncoding

Example...

NSString *string = [NSString stringWithContentsOfURL:kMetOfficeAllSites encoding:NSISOLatin1StringEncoding error:&error];
NSData *metOfficeData = [string dataUsingEncoding:NSUTF8StringEncoding];
id jsonObject = [NSJSONSerialization JSONObjectWithData:metOfficeData options:kNilOptions error:&error];
if (error) {
    //Error handling
} else {
    //use JSON

So I looked at responseJSON in AFJSONRequestOperation.m

- (id)responseJSON {
[self.lock lock];
if (!_responseJSON && [self.responseData length] > 0 && [self isFinished] && !self.JSONError) {
    NSError *error = nil;

    // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
    // See https://github.com/rails/rails/issues/1742
    if ([self.responseData length] == 0 || [self.responseString isEqualToString:@" "]) {
        self.responseJSON = nil;
    } else {
        // Workaround for a bug in NSJSONSerialization when Unicode character escape codes are used instead of the actual character
        // See http://stackoverflow.com/a/12843465/157142
        NSData *JSONData = [self.responseString dataUsingEncoding:self.responseStringEncoding];
        self.responseJSON = [NSJSONSerialization JSONObjectWithData:JSONData options:self.JSONReadingOptions error:&error];
    }

    self.JSONError = error;
}
[self.lock unlock];

return _responseJSON;
}

The code is crashing in the else statement, however this seems to be doing what I was doing previously when using NSJSONSerialization directly and re-encoding the responseString.

I even hardcoded dataUsingEncoding to NSUTF8StringEncoding but it still crashes and I don't understand why?

Note: The above works fine with other JSON feeds, also from other feeds on

http://datapoint.metoffice.gov.uk/ but

http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/sitelist?res=daily&key=

includes the place name Sóil Chaorainn which causes the problem

Matt Price
  • 34,499
  • 6
  • 24
  • 33

1 Answers1

0

The problem seems to be that the text encoding of the response is wrong. There are characters that can't be encoded using ISO-8859-1. This is why the responseString method (see AFURLConnectionOperation.m) returns nil and the JSON serialization fails.

To solve the issue you could subclass AFJSONRequestOperation and override responseStringEncoding in this way to enforce UTF-8 encoding:

- (NSStringEncoding)responseStringEncoding {
    [self.lock lock];
    if (!_responseStringEncoding && self.response) {
        self.responseStringEncoding = NSUTF8StringEncoding;
    }
    [self.lock unlock];

    return _responseStringEncoding;
}
Felix
  • 35,354
  • 13
  • 96
  • 143
  • Isn't that the same as when I tried NSData *JSONData = [self.responseString dataUsingEncoding: NSUTF8StringEncoding]; – Matt Price Mar 15 '13 at 13:34
  • No, because the responseString method uses responseStringEncoding itself and thus would be nil. – Felix Mar 15 '13 at 16:59