Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialVibin Kundukulam
2,819 PointsThrowing error if dictionary doesn't have a specific key (Swift 2.0)
I am trying to throw an error when a specific key doesn't exist in a dictionary within a struct. I'm using data.keys.contains("someKey") where data is my dictionary, but it doesn't seem to be working.
enum ParserError: ErrorType {
case EmptyDictionary
case InvalidKey
}
struct Parser {
var data: [String : String?]?
func parse() throws {
guard let dataTest = data else {
throw ParserError.EmptyDictionary
}
guard let keyTest = data?.keys.contains("someKey") else {
throw ParserError.InvalidKey
}
}
}
let data: [String : String?]? = ["someKey": nil]
let parser = Parser(data: data)
1 Answer
John Ambrose
7,216 PointsSo reading through your code I see two things:
- It does appear to work for checking if the Dictionary is nil! I see only a compiler warning about unused variables [you created dataTest and never used it and keyTest and never used it].
- There is no test though about if the key "someKey" exists. The code simply assigns the value of the contains() method to keyTest. We can fix this though, and use most of the code you've written. We only have to refactor your keyTest guard statement.
First, thing though, a little background about contains(), If you option click on the method you'll see that it returns a Bool result. So, simply calling this method returns either a true or false result. Knowing this we can write this error handler in a really terse manner:
guard dataTest.keys.contains("someKey") == true else {
throw ParserError.InvalidKey
}
Why write it like this?
- We get to use that variable we bound earlier in our 1st guard statement. This is a unique benefit of guard, that we can use instance variables outside of our braces. By using this variable we also make Xcode happy since it hates having unused declarations.
- Since contains() returns a Bool value we can then test that against the desires result (we want a true result otherwise we want the error to be thrown).
And there we go! That single adjustment will correctly throw errors depending on the dictionary we initialize into this struct. You should test it out in xcode using these three variables and replace them for data when you Initialize parser. You can see them in action once you write your do {} catch {} chains.
let data: [String : String?]? = ["someKey": nil]
let nilData: [String : String?]? = nil
let otherData: [String: String?]? = ["otherKey": nil]
FunFact Technically, we could make this code even more terse. Since contains() is a returned Bool, below would be perfectly valid and runs in Xcode as expected:
guard dataTest.keys.contains("someKey") else {
throw ParserError.InvalidKey
}
However, it is ever so slightly less readable. Since it isn't necessarily clear at first glance what we are testing for. But that is likely more of a style issue rather than substance.
PS. I know this has been sitting in the forums for a while but I hope you come back and find this helpful!