I’m currently pulling data via Twitter’s Search API.
Once I receive the data, I am trying to parse and save the data to my TweetDetails class (which is to hold the author’s name, the url of their profile pic, the text of the tweet, the location of the tweet, the tweet id and user id).
In some cases, the Tweets do not have a location (I think it has something to do if they’re retweeted), and the certain dictionary (here being tweetsDict[“place”]) that would otherwise hold that information, instead returns NSNull.
On those occasions, I receive this error
Could not cast value of type ‘NSNull’ (0x1093a1600) to ‘NSDictionary’ (0x1093a0fe8).
Here is my code as I am trying to parse the data and save it to objects in my TweetDetails class
client.sendTwitterRequest(request) { (response, data, connectionError) -> Void in
if connectionError != nil {
print("Error: (connectionError)")
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: [])
if let tweets = json["statuses"] as? [NSDictionary] {
for tweetsDict in tweets {
let text = tweetsDict["text"] as! String
let tweetID = tweetsDict["id_str"] as! String
let place = tweetsDict["place"] as! NSDictionary
// this line ^^ is where the error occurs
let city = place.valueForKey("full_name")
let user = tweetsDict["user"] as! NSDictionary
let userID = user.valueForKey("id_str")
let screenName = user.valueForKey("screen_name")!
let avatarImage = user.valueForKey("profile_image_url_https")!
let tweet = TweetDetails(authors: screenName as! String, profileImages: avatarImage as! String, tweetTexts: text, tweetLocations: city as! String , tweetIDs: tweetID , userIDs: userID as! String)
self.allTweets.append(tweet)
self.tweetTableView.reloadData()
}
}
} catch let jsonError as NSError {
print("json error: (jsonError.localizedDescription)")
}
}
I have tried to create some ‘if-let’ statements to provide alternatives for these occasions, but nothing has worked.
Could someone please help me to create a custom alternative around when certain JSON data returns as NSNull. (Even something as simple as turning my “city” variable into the string “Unknown Location” in the cases when the data returns NSNull).
Thanks in advance and please let me know if there is anything else I can add to provide more clarity to this question.
2
Answers
I see a lot of force data type casting in your code witch is very dangerous, especially when parsing JSON. The correct way of dealing with nullability is not to avoid it by trying to do the same thing we did in objective-c but to prepare to receive nil and react accordingly. Your data model should represent the fact that sometime a tweet have no location so some properties of TweetDetails should be marked as optionals.
The code exemple bellow is completely untested but give you an idea of what your code can look like dealing with nullability.
As others have pointed out, you can use optional binding (
if let
), or, in this case, even easier, just employ optional chaining:This way,
city
is an optional, i.e. if no value was found because there was noplace
orfull_name
entry, it will benil
.It would appear, though, that your
TweetDetails
is force castingcity
to aString
. Does it absolutely require a city? It would be best to change this method so thatcity
was optional and gracefully handlenil
values there. Alternatively, you can replacenil
values forcity
to some other string, e.g. with thenil
coalescing operator:That returns the city if found, and “Unknown city” if not.