roocell roocell - 19 days ago 6
JSON Question

ios NSURLSession JSON parsing to nil in swift (ok in obj-c)

my obj-c code is fine.
can someone help me figure out what's wrong with my swift code?

NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:url]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// handle response
if (error) {
TGLog(@"FAILED");
} else {
NSError* jsonerror;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonerror];
if (jsonerror != nil) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
TGLog(@"response status code: %ld", (long)[httpResponse statusCode]);
TGLog(@"%@", jsonerror);
return;
}
TGLog(@"%@", json);
TGLog(@"status %@ reason %@", [json objectForKey:@"status"], [json objectForKey:@"reason"]);
}
}] resume];


and outputs

2016-11-19 ...._block_invoke:39 status success reason updated


but when I implement it in swift status and reason are nil

var request = URLRequest(url: url)
request.httpMethod = "POST"

URLSession.shared.dataTask(with: request) {data, response, err in
print("Entered user update completionHandler")

DispatchQueue.main.async() {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
if let error = err as? NSError {
print(error.localizedDescription)
} else if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode == 200 {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: Any]
print(json)
let status = json["status"] as? [String:Any]
let reason = json["reason"] as? [String:Any]
// TODO: this is always printing out nil values - haven't figure out the swift problem yet
print("status \(status) reason \(reason)")
} catch let error as NSError {
print(error)
}
}
}

}.resume()


my webpage outputs

{"status":"success","reason":"updated","uuid":"blahblahblahbahaldsh"}

Answer

Read the JSON, status and reason are String rather than a dictionary

 let status = json["status"] as? String
 let reason = json["reason"] as? String

According to the given JSON you could even cast json to [String:String]

let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String:String]

then you get rid of the other type casts

 let status = json["status"]
 let reason = json["reason"]

The result of both lines is optional String. As you seem to be responsible for the web service you can unwrap the optionals if your service sends always the keys status and reason

 let status = json["status"]!
 let reason = json["reason"]!