swift - Data structure for flagging input error in swifty way - Stack Overflow

admin2025-04-25  2

I am writing a tool which accepts certain set of inputs, including some files, parses them, does error checking and if there are no errors then proceeds to do the actual work.

There are about 20 predefined errors with specific error strings in specification for which the tool does input verification.

I can do these error checks without using any data structure (I am new to swift land). But I am intrigued by use of enums and exploring if they make sense in this case.

So, I am planning to write something as follows:

enum ErrorCheck {
     case incorrectFilePathProvided (code: Int, description: String)
     case inputFileIsMissingVersionNumber (code: Int, description: String)
     ....
}

let errorIncorrectFilePathProvided = ErrorCheck.inputFileNotProvided(1, "User has provided incorrect input file")
....

static func validateInputParams(param1: String, param2: NSDictionary) -> NSArray {
     var result: NSMutableArray = []
     if !param1.hasPrefix("/Application") {
        result.add([ErrorCheck.errorIncorrectInputFilePathProvided.code : ErrorCheck.errorIncorrectInputFilePathProvided.description])
     }
     
     if !param2["specificKey"] {
             result.add([ErrorCheck.errorIncorrectInputFilePathProvided.code : ErrorCheck.errorIncorrectInputFilePathProvided.description])
      }
} 

Does this approach makes sense or is there more swifty way to do this?

I am writing a tool which accepts certain set of inputs, including some files, parses them, does error checking and if there are no errors then proceeds to do the actual work.

There are about 20 predefined errors with specific error strings in specification for which the tool does input verification.

I can do these error checks without using any data structure (I am new to swift land). But I am intrigued by use of enums and exploring if they make sense in this case.

So, I am planning to write something as follows:

enum ErrorCheck {
     case incorrectFilePathProvided (code: Int, description: String)
     case inputFileIsMissingVersionNumber (code: Int, description: String)
     ....
}

let errorIncorrectFilePathProvided = ErrorCheck.inputFileNotProvided(1, "User has provided incorrect input file")
....

static func validateInputParams(param1: String, param2: NSDictionary) -> NSArray {
     var result: NSMutableArray = []
     if !param1.hasPrefix("/Application") {
        result.add([ErrorCheck.errorIncorrectInputFilePathProvided.code : ErrorCheck.errorIncorrectInputFilePathProvided.description])
     }
     
     if !param2["specificKey"] {
             result.add([ErrorCheck.errorIncorrectInputFilePathProvided.code : ErrorCheck.errorIncorrectInputFilePathProvided.description])
      }
} 

Does this approach makes sense or is there more swifty way to do this?

Share Improve this question edited Jan 16 at 0:16 HangarRash 15.1k5 gold badges20 silver badges55 bronze badges asked Jan 15 at 18:18 agent.smithagent.smith 9,4669 gold badges41 silver badges50 bronze badges 6
  • Can you resume parsing after one of these errors? If not, you should just use throw. If you can keep going, then accumulate all the errors into a array, stored into some kind of ParseResult object. – Alexander Commented Jan 15 at 18:23
  • Returning an error with the same hard coded values multiple times makes no sense, either throw the error directly or use a unique associated value (string with a descriptive message) for each validation. – Joakim Danielson Commented Jan 15 at 19:17
  • @JoakimDanielson: I am supposed to flag all errors encountered in an output file before throwing "failed" – agent.smith Commented Jan 15 at 19:25
  • I'm assuming there is a unique code corresponding to each type of error, right? incorrectFilePathProvided will always have code 1, inputFileIsMissingVersionNumber will always have code 2, and so on, right? Will the same type of error also have the same description? – Sweeper Commented Jan 15 at 19:42
  • Maybe so but what is the point in using the exact same error then, you can’t tell them apart so how will it matter if it’s one or multiple? (Or have you just posted a bad example above?) Unrelated but don’t use old NS types, use native swift types instead. – Joakim Danielson Commented Jan 15 at 19:55
 |  Show 1 more comment

1 Answer 1

Reset to default 1

I think you might have misunderstood how enums work, because if each every has a unique code and message, code and message should not be the associated values of each case.

If you just want an error type that consists of a code and a message, just write a struct with those properties, and static lets for each error.

struct ErrorCheck {
    let code: Int
    let message: String
    
    private init(code: Int, message: String) {
        self.code = code
        self.message = message
    }
    
    static let incorrectFilePathProvided = ErrorCheck(code: 1, message: "User has provided incorrect input file")
    static let inputFileIsMissingVersionNumber = ErrorCheck(code: 2, message: "Input file is missing a version number")
}

You can also use an enum, but without associated values. I personally find the switches a bit annoying to write though.

enum ErrorCheck {
    case incorrectFilePathProvided
    case inputFileIsMissingVersionNumber
    
    var code: Int {
        switch self {
        case .incorrectFilePathProvided:
            1
        case .inputFileIsMissingVersionNumber:
            2
        }
    }
    var message: String {
        switch self {
        case .incorrectFilePathProvided:
            "User has provided incorrect input file"
        case .inputFileIsMissingVersionNumber:
            "Input file is missing a version number"
        }
    }
}

For validateInputParams, it should not take a NSDictionary and return an NSArray. You should avoid using Objective-C collection types when writing Swift.

// param2 can be [AnyHashable: Any] if you are not sure about the key type
func validateInputParams(param1: String, param2: [String: Any]) -> [ErrorCheck] {
    var errors = [ErrorCheck]()
    if !param1.hasPrefix("/Application") {
        errors.append(.incorrectFilePathProvided)
    }
    
    if param2.keys.contains("version") {
        errors.append(.inputFileIsMissingVersionNumber)
    }
    
    return errors
}

I would also suggest conforming to Error:

extension ErrorCheck: Error {}

This isn't necessary for validateInputParams since it returns the errors instead of throwing them, but who knows what you might need in the future?

Conforming to LocalizedError is also an option if the message is supposed to be displayed to the end user. In this case you should rename message to errorDescription. Other APIs that needs to display your error will use that property.

转载请注明原文地址:http://anycun.com/QandA/1745563206a90925.html