0

I've created a JSON parser and error class for it:

enum ParseError: Error {

    case cannotParseField(fieldName: String)
    case cannotFormatDate(fieldName: String)
    case cannotFormatEnum(fieldName: String)

}

class SPUserParser {

    static func parseSPUsers(data:Data) throws -> [SPUser] {
        var spUsers:[SPUser] = []
        let json = JSON(data: data)

        if let array = json["value"].array {
            for user in array {

                guard let id = user["Id"].int else { throw ParseError.cannotParseField(fieldName: "Id") }
                //PARSE OTHER STUFF...

            }
        }

        return spUsers
    }

}

Then when I'm trying to use my parser like this:

sendQuery(requestMethod: "GET", url: requestUrl, body: "", includeFormDigest:false, completed: { (data:Data) in

            var result = ""
            do {
                let newUsers:[SPUser] = try SPUserParser.parseSPUsers(data: data)
                self.spUsers.removeAll()
                self.spUsers.append(contentsOf: newUsers)
            }
            catch ParseError.cannotParseField(let fieldName) {
                result = "cannotParseField: \(fieldName)"
            }
            catch ParseError.cannotFormatDate(let fieldName) {
                result = "cannotFormatDate: \(fieldName)"
            }
            catch ParseError.cannotFormatEnum(let fieldName) {
                result = "cannotFormatEnum: \(fieldName)"
            }
            print(result)

The project won't compile.

The error is: Invalid conversion from throwing function of type '(Data) throws -> ()' to non-throwing function type '(Data) -> ()'

To fix this error I had to add catch {} after this three catches. Why I have to do this?

My code is based on Apple documentation: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html

Makalele
  • 7,431
  • 5
  • 54
  • 81
  • 1
    Well, without the generic `catch {}`, the catch statement is not exhaustive. `parseSPUsers` could still throw an error unrelated to the `ParseError` enum. Hence, a code block that uses it cannot be marked as non-throwing until all potential errors are caught. – crizzis Sep 21 '17 at 08:21
  • Check out vendingMachine example in Apple documentation. They don't have empty catch {} on the end. – Makalele Sep 21 '17 at 08:25
  • 1
    Have you read the sentence just above it? 'For example, the following code handles all three cases of the VendingMachineError enumeration, but all other errors **have to** be handled by its surrounding scope'. They don't show you the code surrounding the do-catch statement, but were the code wrapped in a block, the block would need to be declared as throwing. – crizzis Sep 21 '17 at 08:27
  • Not related but why are you using a temporary variable, remove all items in `spUsers` and then appending the new Items? **One** line `self.spUsers = try SPUserParser.parseSPUsers(data: data)` does exactly the same and is much more efficient. – vadian Sep 21 '17 at 08:27
  • @crizzis Thanks for the clarification, I missed that one. So swift compiler isn't smart enough to check if I've exhausted all exceptions. – Makalele Sep 21 '17 at 08:47
  • @Makalele: Indeed. Compare https://stackoverflow.com/questions/45104487/exhaustive-catch-blocks-without-empty-or-wildcard-in-swift-3-1, which has links to more related questions in the comments. – Martin R Sep 21 '17 at 08:58

1 Answers1

0

What you can do to simplify your code is using the let keyword in your catch like this :

do {
    try SPUserParser.parseSPUsers(data: data)
    // Your Stuff
} catch let parseError as ParseError {
    result = handle(parseError)
} catch {
    // Handles other kinds of errors
    result = "other kind of error: \(error)"
}

And in the handle method that I used, you check which kind of ParseError it is, basically just a switch and then handle it accordingly

func handle(_ parseError: ParseError)
    switch parseError {
    case .cannotParseField(let fieldName):
        return "cannotParseField: \(fieldName)"
    case .cannotFormatDate(let fieldName):
       return "cannotFormatDate: \(fieldName)"
    case .cannotFormatEnum(let fieldName):
        return "cannotFormatEnum: \(fieldName)"
}
NlsGladiatus
  • 205
  • 2
  • 6