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 trialPaul Je
4,435 PointsNot sure about the syntax to create two guard statement cases for each throw instance
Can anybody help me find the statements needed to solve this problem? I feel like I don't really understand how to actually get the list of keys from the key function and how to use contains in order to first call the array before checking if any value exists for either the key or the value of the key.. thanks!
enum ParserError: ErrorType {
case EmptyDictionary
case InvalidKey
}
struct Parser {
var data: [String : String?]?
func parse(arrayOfKeys: keys) throws {
guard var someKey = dict["data": String ] else {
throw ParserError.EmptyDictionary("the data and or the value of the key cannot be found in the dictionary")
}
guard var someKey = dict[ nil : String] {
throw ParserError.InvalidKey("the key is invalid since it itself does not exist in dictionary, so therefore the value cannot either")
}
}
}
let data: [String : String?]? = ["someKey": nil]
let parser = Parser(data: data)
5 Answers
Kyler Smith
10,110 PointsThis one is definitely tough!
First, the challenge in part 1 asks you to construct the parse function. It doesn't explicitly ask you to add any parameters to the method, so I would recommend removing those first.
parse() throws {
// Your code goes here
}
Next, it asks for you to throw an error if the data coming in is nil. They give you the variable data of type optional dictionary, so you need to see if the optional dictionary is nil or has some value. A guard statement would be perfect for this!
guard let dict = data else {
// this is where you put code that executes if the guard statement returns nil.
}
Then it asks for you to throw another error if the key "someKey" doesn't exist. This one is a little tricky so I'll jot it down and then explain.
guard data?.keys.contains(/*the key you're looking for*/) == nil else {
// Executes if "someKey" returns nil
}
Basically, this guard statement looks for an optional variable called data. If this passes, then it looks at every key [because this is a dictionary, this part will fail if the optional data is an optional string, or any other optional type.] Then, from the keys it looks for a key called "someKey". The 'data?' inside the guard statement is need because you need to let the computer know it's dealing with an optional.
Let me know if other questions arise or I wasn't clear! Good luck!
Ben Shockley
6,094 PointsTo get the keys from the dictionary you can do this.
let keys = someDictionary.keys
This will return an array to keys
of all the keys in the dictionary.
Then you can use .contains
to see if that key exist in the dictionary by doing this.
if keys.contains("some string") {
// do something
} else {
// do something else
}
Does this help at all?
John Ambrose
7,216 PointsI really really want to understand that last portion of code. can you help Kyler?
As I understand it the guard statement will only execute the else clause if it evaluates to false, right?
But the .contains() method returns a bool type.
Doesn't "true == nil" evaluate to false AND "false == nil" also evaluates to false?
So if I'm understanding this, regardless of whether the dictionary has a key that matches the string we put in .contains(), as long as there is some sort of key of type string in data wouldn't the guard statement ALWAYS throws the error?
What am I missing here? I'm sure its simple.
I actuallly ended up using:
guard data?.keys.contains("someKey") == true else {
throw ParserError.InvalidKey
}
and of course the step 1 accepted your code but also my code when I went back.
Kyler Smith
10,110 PointsConvention is to compare the value to nil to determine if a value is there or if a value is not there. Using true and false will do the same thing. The whole guard statement is evaluated to determine the boolean value that checks.
/*
These statements will all pass
You are asking if this key exists and if it does not exist, throw the error.
*/
guard (data?.keys.contains("someKey") == true) else {
throw ParserError.InvalidKey
}
guard (data?.keys.contains("someKey") != false) else {
throw ParserError.InvalidKey
}
guard (data?.keys.contains("someKey") == nil) else {
throw ParserError.InvalidKey
}
/*
These statements evaluate to false and fail the challenge.
You are asking if that key exists and if it does, throw the error.
*/
guard (data?.keys.contains("someKey") != true) else {
throw ParserError.InvalidKey
}
guard (data?.keys.contains("someKey") == false) else {
throw ParserError.InvalidKey
}
guard (data?.keys.contains("someKey") != nil) else {
throw ParserError.InvalidKey
}
Play around with it and let me know if it's still confusing!
John Ambrose
7,216 PointsHi Kyler! I have finally wrapped my head around this exercise and wanted to share my findings with you. I think perhaps you might be mistaken about this exercise.
While the == nil comparison does pass (maybe because the case successfully evaluates, it just evaluates to false), no matter what value is placed in the key for the var data, your parser as written will always throw the InvalidKey error.
However, if we use the below code:
struct Parser {
var data: [String : String?]?
func parse() throws {
guard let dict = data else {
throw ParserError.EmptyDictionary
}
guard dict.keys.contains("someKey") == true else {
throw ParserError.InvalidKey
}
/// The print statement is not part of the exercise but I used it to test when both error checks had passed
print("No Errors have been found.")
}
}
We can actually trigger the EmptyDictionary, the InvalidKey, or just pass all checks and perform some other work (like printing a success message to console).
We can test this in a playground too! Just set up the following variables:
let data: [String : String?]? = ["someKey": nil]
let nilData: [String : String?]? = nil
let otherData: [String: String?]? = ["otherKey": nil]
Then initialize a Parse struct using any of the above variables you like.
let parser = Parser(data: nilData)
The parse method along with a pattern matching Do catch combo like listed below, will print an error for each type of error we created with our variables. Otherwise, if we use the valid "data" we print the success line to the console.
do {
try parser.parse()
} catch ParserError.EmptyDictionary() {
print("The Dictionary does not exist")
} catch ParserError.InvalidKey() {
print("Key 'someKey' doesn't exist in this Dictionary")
}
If you already knew all this, then ignore me. But I finally understand all of this section!
Sidenote: we can be more terse with "guard dict.keys.contains("someKey") == true" . Since the "contains()" method actually returns a Bool value, we could drop the "== true" altogether. I think the "== true" is slightly more readable but that is my opinon!
Paul Je
4,435 PointsWill this code work on the challenge to let me pass? lol
John Ambrose
7,216 PointsHi Paul!
Yes, one you delete my Print Statement that I added inside of the struct (the one with the commented text above it), all the above code should get you through the challenge. Let me know if there is something specific which you aren't understanding as I feel like I've firmly grasped this specific challenge after banging my head against it.
Paul Je
4,435 PointsPaul Je
4,435 PointsHi Kyler,
I did as you suggested, but I still have 3 errors and I'm unsure of how to complete it.. it truly is one of the hardest questions I've tried. My code has 3 errors currently looks like this:
swift_lint.swift:8:12: error: argument for generic parameter 'Key' could not be inferred let keys = Dictionary.keys ^ swift_lint.swift:17:46: error: cannot call value of non-function type 'ParserError' throw ParserError.EmptyDictionary("the data in the array dict has a nil value. I.E, the value is nil, not the key") ~~~~~~~~~~~~~~~~~~~~~~~~~
^ swift_lint.swift:21:41: error: cannot call value of non-function type 'ParserError' throw ParserError.InvalidKey("the key is invalid since it itself does not exist in dictionary, so therefore the value cannot either") ~~~~~~~~~~~~~~~~~~~~^Am I using the syntax correctly? Which dictionary am I supposed to refer to in order to callback the key?
Kyler Smith
10,110 PointsKyler Smith
10,110 PointsPaul, If you could please post your code so I can better assist you. The format is to use three backticks followed by the name of the language on the first line by itself and then three backticks on the last line by itself. You can also reference the Markdown Cheatsheat on the hyperlink just above the post comment button. Thank you!