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 trial

iOS Error Handling in Swift 2.0 Error Handling Handling Errors

Paul Je
Paul Je
4,435 Points

Soo Lost .. Not sure where to begin

Catch & Do clauses seem unfamiliar now, and getting discouraged. It's hard to know whats going on.. I copied the model of the video lecture and went from there, but not sure how to initialize the Parser Error in the catch clause, and why I am even doing so lol. Syntax behind how to print the error message seem unfamiliar, and I don't understand what a "let key" initializer meant, which I will probably review again soon. Any help at all would be much appreciated!

error.swift
enum ParserError: ErrorType {
    case EmptyDictionary
    case InvalidKey
}


struct Parser {
    var data: [String : String?]?

    func parse() throws {

        guard let dict = data else {
            throw ParserError.EmptyDictionary
        }

        guard (data?.keys.contains("someKey") == true) else {
            throw ParserError.InvalidKey
        }

        func parseThisArray(parser: Parser, message: String) {}

        let wordToBeParsed = data["Wussup" : "NotMuch"?]?

        do {
            let keyAndValueCheckup = try parse(wordToBeParsed)
            parseThisArray(parser, message: "")


        } catch ParserError() {
            print("Error! Error!")
        }
    }

}

let data: [String : String?]? = ["someKey": nil]
let parser = Parser(data: data)

2 Answers

John Ambrose
John Ambrose
7,216 Points

Aaron's code looks like it might work! But if we want to follow along with the exercises the parse method will want to use the guard key words. But first lets start over with the original data provided by Task 1:

enum ParserError: ErrorType {
    case EmptyDictionary
    case InvalidKey
}

struct Parser {
    var data: [String : String?]?

    func parse() throws {

        }
    }
}

let data: [String : String?]? = ["someKey": nil]
let parser = Parser(data: data)

Okay, starting here the first task asks for us to check for two specific errors that in the parse function that it might run into.

  • We want to throw an error if the dictionary we are parsing is nil
  • We also want to throw an error if the dictionary does NOT have a key called "someKey"

So we can do this with two guard evaluations (which are awesome as we can avoid the Pyramid of Doom Aaron demonstrated above).

        guard let dict = data else {
            throw ParserError.EmptyDictionary
        }
        guard dict.keys.contains("someKey") == true else {
            throw ParserError.InvalidKey

Phew! that was a lot of stuff we just pasted in there what does it all mean?

  1. This guard statement assigns the dictionary value from data to a variable called "dict" if a dictionary exists. If there is no dictionary (meaning if data was nil) we would then throw the EmptyDictionary error.
  2. Since we used a guard statement that variable "dict" can be used OUTSIDE the braces this will let us access the keys parameter for the dictionary we assigned to it, and then call the method "contains" to check if the specific key "someKey" is in that dictionary

Now we can start talking about the Do Catch clauses! We will have the Do / Catch portion outside our Parse Struct because... I don't think we can call it inside the struct like you tried to do above.

We've gone through the trouble to check for errors, and currently we've been taught only one way to actually find out which error triggered. We have to run the method within a Do clause, and then chain catch clauses for each error type we identified if we want to actually make sense of which error specifically we might have encountered when we "try"-ed to "parse" our "parser".

//So lets open our Do clause.
do {
    try parser.parse()


//this is our first error check.  If our parse method had been passed
//nil this error would trigger first and print to the console    
} catch ParserError.EmptyDictionary() {
    print("The Dictionary does not exist")

//this is our second error check.  If our parse method had been passed
//valid Dictionary but none of the keys were "someKey" this would print to our console

} catch ParserError.InvalidKey() {
    print("Key 'someKey' doesn't exist in this Dictionary")
}

Now, you'll notice that if you tossed all of this into a playground it would look like no errors had been thrown. This is because the Parser generated with a Dictionary that contained a key of "someKey"

You can test the code works as expected though if you create two other constants

let nilData: [String : String?]? = nil
let otherData: [String: String?]? = ["otherKey": nil]

If you were to create a new parser and pass one of those constants above and then run the above do { try } catch{...} catch{...} on that new parser struct, you should throw an error and see the benefits of the Error Handling come to life.

Aaron Bilenky
Aaron Bilenky
13,294 Points

For the first part first you need to check if the data dictionary is nil, if it is, throw the EmptyDictionary error.

if let dict = data {

} else {
      throw  ParserError.EmptyDictionary
}

If the data is not nil then you just need to check if "someKey" is in the dictionary. If not then throw the InvalidKey error

if let dict = data {

      if dict.keys.contains("someKey") {

      } else  {
        throw ParserError.InvalidKey
      }
} else {
      throw  ParserError.EmptyDictionary
}

For the second part you just call the parse method inside a do block. In the catch blocks for each of the error cases just use print() to display an error message of your choice.

do {
  try parser.parse()
} catch ParserError.EmptyDictionary {
  print("Error: EmptyDictionary")
} catch ParserError.InvalidKey {
 print("Error: InvalidKey") 
}