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 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 let
s 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 switch
es 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 throw
ing 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.