hellosheikh
hellosheikh

Reputation: 3015

Could not cast value of type 'NSNull' to 'NSString'

I am having a very weird problem which I am not able to figure it out of what is going wrong here.

Here is my code

func updateSearchResultsForSearchController(searchController: UISearchController) {
    filterTableData.removeAll(keepCapacity: false)
    let searchWord = searchController.searchBar.text!

    getCountriesNamesFromServer(searchWord)

    let searchPredict = NSPredicate(format: "SELF CONTAINS[c] %@", searchController.searchBar.text!)

     newTableData = [String]()

    for var i = 0; i < self.dict.count - 1; i++ {

        let cityName = (((self.dict["\(i)"] as?NSDictionary)!["City"] as?NSDictionary)!["name"] as?NSString)! as String
       let countryName = (((self.dict["\(i)"] as?NSDictionary)!["Country"] as?NSDictionary)!["name"] as?NSString)! as String

            print("countryName is \(countryName)")





    newTableData.append(cityName)
    }
    print("newTableData is \(newTableData)" )
    let array = (newTableData as NSArray).filteredArrayUsingPredicate(searchPredict)
    print("array is\(array)")
    filterTableData = array as! [String]
    self.tableView.reloadData()
}

Program is crashing at this line

let countryName = (((self.dict["\(i)"] as?NSDictionary)!["Country"] as?NSDictionary)!["name"] as?NSString)! as String

when I type first character in the search box all works fine but as soon as I type second character in the searchBox program crashes and it gives me this error

Could not cast value of type 'NSNull' (0x1a03c3768) to 'NSString' (0x1a03cd798).

and for your Information countryNames exist in the dict variable but I don't know why its giving me null value and why city name is successfully working because country also exist in the same array from which I am getting the city

UPDATE:

This line prints country name successfully

  print("countryName is \(countryName)")

Upvotes: 3

Views: 8836

Answers (3)

Vikash Yadav
Vikash Yadav

Reputation: 11

@gnasher729 Explained it very well, but to solve your problem you should use the "?" instead of "!"

so while parsing the data from the code below

 let countryName = (((self.dict["\(i)"] as?NSDictionary)!["Country"] as NSDictionary)!["name"] as?NSString)! as String

use the code as

let countryName = (((self.dict["\(i)"] as?NSDictionary)!["Country"] as?NSDictionary)!["name"] as? NSString)? as String ?? ""

or

let countryName = ((self.dict["\(i)"] as?NSDictionary)!["Country"] as?NSDictionary)!["name"] as? String ?? ""

Thanks

Upvotes: 1

Kevin Machado
Kevin Machado

Reputation: 4187

You received a list of country from your server at this line

getCountriesNamesFromServer(searchWord)

But I think that its returning you a list without all datas completely set.

for var i = 0; i < self.dict.count - 1; i++ {

            let cityName = (((self.dict["\(i)"] as?NSDictionary)!["City"] as?NSDictionary)!["name"] as?NSString)! as String
            let countryName = (((self.dict["\(i)"] as?NSDictionary)!["Country"] as?NSDictionary)!["name"] as?NSString)! as String

            print("countryName is \(countryName)")

            newTableData.append(cityName)
        }

On the first iteration of your loop the name value is set correctly so it works but at the second iteration, it is, in my opinion, null and you cannot cast NSNull to NSString so the application crashes.

Before casting to NSString, if you are not sure of the server response, you must try if the dictionary contains the name key and if the value is set. If it is, you can try to cast it.

If you want, you can also use an external library SwiftyJSON to simplify the parsing of JSON response.

Upvotes: 0

gnasher729
gnasher729

Reputation: 52632

Well, they tell you what the problem is: You've got a result of type NSNull, and NSNull cannot be converted to NSString.

Most likely you are processing JSON, and JSON data often contains null values.

Go away from your labyrinth of ? and !

Write some code that helps you. Remember that any ! will crash your application if you don't get what you expect.

When you access the key "name" in a dictionary, you need to handle the case that there is a string (nice for you), nothing (key doesn't exist, very common), null (the server tells you explicitly that there is nothing, very common), a number, bool, dict or array.

For each of these cases, tell me what you want as a result: A crash? An optional string that is nil? An empty string? Typically you want a string if it is there, possibly a number converted to a string if it is a number, and either nil or an empty string if the key isn't there or null, and either a crash or nil if you get a bool, dictionary or array.

Then write a function that returns exactly that. And then you use it. When you write (... as? NSString)! you tell the compiler that you want a crash if it's not a string, and that's what you got.

Upvotes: 4

Related Questions