1

I have a function assignName(name:) which throws an error. When that function is called from a do block with multiple catch, It shows the error as:

Errors thrown from here are not handled because the enclosing catch is not exhaustive 

My Code is:

enum PersonError: ErrorType {
    case IsNotAPerson
    case IsNotAGoodPerson
    case IsNotAValidPerson
}

func assignName(name: String?) throws {
    guard name != nil else {
        throw PersonError.IsNotAPerson
    }
    personName = name
}
func catchingSpecificError() {
    do {
        try assignName(nil) // Compiler Error displays at this line.

    }catch PersonError.IsNotAPerson {
        print("Propagated error is caught in catch on case .NotAPerson")
    }     
}

Thanks in Advance!

Qbyte
  • 12,753
  • 4
  • 41
  • 57
Shanmugaraja G
  • 2,778
  • 4
  • 31
  • 47
  • 3
    I just realized this is quite the duplicate: http://stackoverflow.com/questions/30720497/swift-do-try-catch-syntax?rq=1 – dfrib Jan 06 '16 at 13:17

1 Answers1

5

You need to include a default catch block (much like when using a switch case) to make your error handling exhaustive; in case the error thrown is not one of the ones you specify.

func catchingSpecificError() {
    do {
        try assignName(nil) // Compiler Error displays at this line.

    }catch PersonError.IsNotAPerson {
        print("Propagated error is caught in catch on case .NotAPerson")
    }catch {
        print("default..")
    }
}

Slightly off-topic, but I assume personName = name refers to a class property personName that we cannot see in your example above.


With the default catch block added, you mention in the comments below that function catchingSpecificError() does not cast the error you expect; or rather, the default catch block catches your error.

Now, since I don't know the context of your code, I cannot infer what is actually going wrong in your case. I'll post a working example for your below where---in the context of this question---the throw and catch work as expected. Note however that your use of the guard block is somewhat out of by convention. Usually you make use of guard just like if let blocks, i.e., guard let name = name else { .., which will enter the guard block if name contains nil.

Anyway, consider the following fully working example:

enum PersonError: ErrorType {
    case IsNotAPerson
    case IsNotAGoodPerson
    case IsNotAValidPerson
}

class Person {
    var personName : String? = ""

    func assignName(name: String?) throws {
        guard name != nil else {
            throw PersonError.IsNotAPerson
        }

        personName = name
    }

    func catchingSpecificError() {
        do {
            try assignName(nil)

        }catch PersonError.IsNotAPerson {
            print("Propagated error is caught in catch on case .NotAPerson")
        }catch {
            print("default..")
        }
    }
}

var myPerson = Person()
var myName : String? = nil

myPerson.catchingSpecificError()
/* Prints: "Propagated error is caught in catch on case .NotAPerson" */

As expected, we catch PersonError.IsNotAPerson thrown by function assignName. Hopefully you can make use of this example your get your own code (the parts that you haven't shown us in your question) working.

dfrib
  • 70,367
  • 12
  • 127
  • 192
  • Thanks, I tried with default catch. In my case, The throwing methods assignName(nil) throws PersonError.IsNotAPerson error, But the default catch is executed, not the catch I specifically should catch the PersonError.IsNotAPerson error. – Shanmugaraja G Jan 07 '16 at 13:39
  • @ShanmugarajaG Happy to help. I added an example for you, hopefully you can compare this with your own implementation (that you haven't shown us) and see why your case doesn't work as intended. If you still get unexpected results, possibly add more details to your question. – dfrib Jan 07 '16 at 13:58
  • 1
    Thanks, It worked, Instead of passing nil to the assignName(), I passed a parameter with type String? and value is nil. It worked yaar. – Shanmugaraja G Jan 19 '16 at 12:07