We are trying to make a function to get JSON from an API..We know that this is giving us NIL but we dont know why the error is occuring. The exact error message that we got was
[] 2020-08-01 16:29:26.501199-0400 HEFT[97766:2952325] [] nw_proxy_resolver_create_parsed_array [C1 proxy pac] Evaluation error: NSURLErrorDomain: -1003 Could not cast value of type 'NSNull' (0x7fff87a92380) to 'NSString' (0x7fff87b502e8). 2020-08-01 16:29:26.670549-0400 HEFT[97766:2952139] Could not cast value of type 'NSNull' (0x7fff87a92380) to 'NSString' (0x7fff87b502e8). (lldb)
We have tried messing around the code to find a solution and we tried to use some other questions but none of them were related with what we were trying to achieve.
func getJson() {
if let url = URL(string: "https://api.weather.gov/alerts/active?area=GA") {
URLSession.shared.dataTask(with: url) { (data:Data?, response:URLResponse?, error:Error?) in
if error == nil {
if data != nil {
if let json = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject] {
DispatchQueue.main.async {
//if let rawfeatures = json["features"] {
var rawfeatures = json["features"] as! [Dictionary< String, AnyObject>]
var keepgoingfeatures = rawfeatures.count
var FeatureIndex = 0
while keepgoingfeatures != 0{
let currentRawFeature = rawfeatures[FeatureIndex]
let currentRawFeatureProperties = currentRawFeature["properties"]
let currentFeature = Feature()
currentFeature.event = currentRawFeatureProperties!["event"] as! String
currentFeature.description = currentRawFeatureProperties!["description"] as! String
currentFeature.instructions = currentRawFeatureProperties!["instruction"] as! String
currentFeature.urgency = currentRawFeatureProperties!["urgency"] as! String
keepgoingfeatures -= 1
FeatureIndex += 1
}
}
}
}
} else {
print("We have an error")
}
}.resume()
}
}
Some of these alerts have
null
forinstructions
. I’d suggest defining your object to acknowledge that this field is optional, i.e. that it might not be present. E.g.And, when parsing it, I might suggest getting rid of all of those forced unwrapping operators, e.g.
A few other observations:
I’ve removed all of the forced casting (the
as!
). You don’t want your app crashing if there was some problem in the server. For example, not infrequently I receive a 503 error. You don’t want to crash if the server is temporarily unavailable.The docs say that you should set the
User-Agent
, so I’m doing that above. Obviously, set thedomain
andemail
string constants accordingly.While you can build the URL manually, it’s safest to use
URLComponents
, as that will take care of any percent escaping that might be needed. It’s not needed here, but will be a useful pattern if you start to get into more complicated requests (e.g. need to specify a city name that has a space in it, such as “Los Angeles”).I’d suggest the above completion handler pattern so that the caller can know when the request is done. So you might do something like:
I’m returning the
URLSessionTask
in case you might want to cancel the request (e.g. the user dismisses the view in question), but I’ve marked it as a@discardableResult
, so you don’t have to use that if you don’t want.I’ve replaced the tower of
if
statements with aguard
statement. It makes the code a little easier to follow and adopts an “early exit” pattern, where you can more easily tie the exit code with the failure (if any).Personally, I’d suggest that you take this a step further and get out of manually parsing
JSONSerialization
results. It’s much easier to letJSONDecoder
do all of that for you. For example: