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 trialJUNSEI TEI
2,055 PointsError Handling
enum ParserError: ErrorType {
case EmptyDictionary
case InvalidKey
}
struct Parser {
var data: [String : String?]?
func parse() throws {
guard data?.isEmpty == false else {
throw ParserError.EmptyDictionary
}
guard let a = data?["someKey"] else {
throw ParserError.InvalidKey }
}
}
let data: [String : String?]? = ["someKey": nil]
do {
let parser = Parser(data: data)
try parser.parse()
} catch ParserError.InvalidKey {
print("key does not exist")
} catch ParserError.EmptyDictionary {
print("The data is nill")
}
5 Answers
Steven Deutsch
21,046 PointsHey JUNSEI TEI,
Let's break down this challenge step by step. It's a tough one. The first task asks us to do two things.
- Check if our parser data is equal to nil
- Check if the data contains a key called "someKey"
If any of these two checks is not true, we want to throw an error.
1) To check if the data is equal to nil, we can use a guard statement to do optional binding. If data is equal to nil, we will immediately execute the else block and throw the error .EmptyDictionary.
2) To check if the data contains a key called "someKey" we will also use a guard statement with optional binding. First we access the keys property of data. This property returns an array of keys from the data dictionary. However, because data is an optional value, before we use dot syntax to access the property, we must conditionally unwrap it.
Next we have to use a where clause to add an additional check to this statement. If accessing the keys property on data did not return nil, the array of keys will be assigned to the local constant named keysArray. We then want to check if that keysArray contains the key "someKey". We can do this with the contains() method. If the keysArray does not contain "someKey", the else block will be executed and we will throw the error .InvalidKey.
The second/third tasks asks us to:
- Call the parser function on the parser data
- Handle the errors thrown
1) Because the parser method has been marked as a function that throws, in order to call it we need to use the 'try' keyword. When calling functions that throw errors, it is typical to do them inside a do/catch block. The do block is where we do our function calls, and the catch block is where we handle the errors that are thrown.
2) Now for each catch block we can execute some sort of functionality for each type of error thrown. You do this by writing the name of the enum and its specific member that you are checking for. In this example, we are just going to print a message to the console to give the user a little information about which error was thrown.
enum ParserError: ErrorType {
case EmptyDictionary
case InvalidKey
}
struct Parser {
var data: [String : String?]?
func parse() throws {
guard let parserData = data else {
throw ParserError.EmptyDictionary
}
guard let keysArray = data?.keys where keysArray.contains("someKey") else {
throw ParserError.InvalidKey
}
}
}
let data: [String : String?]? = ["someKey": nil]
let parser = Parser(data: data)
do {
try parser.parse()
} catch ParserError.EmptyDictionary {
print("The dictionary was empty.")
} catch ParserError.InvalidKey {
print("The dictionary did not contain the specified key.")
}
Hope this helps!
kols
27,007 PointsSteven provided a wonderful explanation of the concepts in this challenge above (thanks!!), but unfortunately that code no longer works for this challenge as it was posted a while back. This was a tricky one for me, so I'm adding the answer that worked for me below (currently Swift 4) in the hopes it helps someone else out:
enum ParserError: Error {
case emptyDictionary
case invalidKey
}
struct Parser {
var data: [String : String?]?
func parse() throws {
guard data != nil else {
throw ParserError.emptyDictionary
}
guard data?.keys.contains("someKey") == true else {
throw ParserError.invalidKey
}
}
}
let data: [String : String?]? = ["someKey": nil]
let parser = Parser(data: data)
do {
try parser.parse()
} catch ParserError.emptyDictionary {
print("The dictionary is empty.")
} catch ParserError.invalidKey {
print("The key 'someKey' does not exist.")
}
Linus Karlsson
7,402 PointsThese long questions are the ones that eventually I just end up using copy/paste if I'm honest.
It really doesn't feel like a good task for beginners...
Thank you so much though!
Alex Millius
iOS Development Techdegree Student 5,468 PointsThanks for your response Steven Deutsch.
There is a small room for improvement in your code.
In your function parse, your guard is:
guard let a = data?["someKey"] else {
throw ParserError.InvalidKey
}
This way you defined a value "a" that is never used. This is not a good practice.
Maybe you could replace it by a "!= nil" check.
guard data?["someKey"] != nil else {
throw ParserError.InvalidKey
}
Steven Deutsch
21,046 PointsOh very interesting Alex. I like it. Good point!
John Hendrix
21,844 PointsThe above coded answer no longer compiles in 2017. Can someone help with the correct answer. I have tried everything I can think of with no luck so far.
Bummer! Your code could not be compiled. Please click on "Preview" to view the compiler errors.
swift_lint.swift:16:39: error: expected expression in conditional
guard let keysArray = data?.keys, where keysArray.contains("someKey") else {
^
swift_lint.swift:16:80: error: braced block of statements is an unused closure
guard let keysArray = data?.keys, where keysArray.contains("someKey") else {
^
swift_lint.swift:3:19: error: 'ErrorType' has been renamed to 'Error'
enum ParserError: ErrorType {
^~~~~~~~~
Error
swift_lint.swift:3:6: error: type 'ParserError' does not conform to protocol 'RawRepresentable'
enum ParserError: ErrorType {
^
Swift.RawRepresentable:96:20: note: protocol requires nested type 'RawValue'; do you want to add it?
associatedtype RawValue
^
swift_lint.swift:13:27: error: thrown expression type 'ParserError' does not conform to 'Error'
throw ParserError.EmptyDictionary
~~~~~~~~~~^~~~~~~~~~~~~
swift_lint.swift:17:27: error: thrown expression type 'ParserError' does not conform to 'Error'
throw ParserError.InvalidKey
~~~~~~~~~~^~~~~~~~
swift_lint.swift:16:80: error: expression resolves to an unused function
guard let keysArray = data?.keys, where keysArray.contains("someKey") else {
^
Bekzod Rakhmatov
7,419 PointsDid you get the solution of this problem? (https://teamtreehouse.com/community/swift-3-error-handling-code-challenge-help) somebody left this solution it may help you out there!
John Hendrix
21,844 PointsHi Bekzod Rakhmatov , I did finally get it, but thank you for checking and thanks for providing the link for others!
JUNSEI TEI
2,055 PointsJUNSEI TEI
2,055 PointsYour answer helps me a lot!!! Thx
Dustin Bryce Flanary
17,663 PointsDustin Bryce Flanary
17,663 PointsI especially appreciated your explanation, thank you!