Let me prefix with why I think this is not a duplicate of How to provide a localized description with an Error type in Swift?
The answers provided will still result in some static/class function call and not an initializer style or require casting to NSError (which I like to avoid).
A brief summery of the reasons:
A Swift function that throws
does not declare the error type. We cannot enforce the catch
to pass a custom type that simply conforms to the Error
protocol. Knowing that, on the do-catch side, we get no help from the compiler as to what type (if custom) of error we get and by default we'll expect the known NSError
properties. Otherwise, we need to simply rely on textual documentations explaining the type of errors we can catch, as the catch will simply pass an Error
type.
Now, unlike NSError, Error is a protocol where the properties we get in userInfo
are read only. So we resort to constructing an NSError type, and casting it as Error.
I am trying to create a simple clean struct that return an Error type (not NSError) where I can throw like:
throw MYError(domain: "com.somthing.error", code: 0, userInfo: [NSLocalizedDescriptionKey : "Something bad happened"])
Main issue is that the only way to set the NSLocalizedDescriptionKey
, is by initializing an NSError object. Doing so will require casting to Error
type (which is something I'm trying to avoid).
I first tried to use extension Error {...
, but cannot use an initializer.
If I use a struct conforming to Error protocol (struct MyError: Error {...
), I still have the problem of localizedDescription
is get only.
What I use is actually something like:
struct MYError: Error {
static func with(domain: String = "com.somthing.error", code: Int = 0, localizedDescription: String) -> Error {
return NSError(domain: domain, code: code, userInfo: [NSLocalizedDescriptionKey : localizedDescription]) as Error
}
}
Which I can use like:
throw MYError.with(localizedDescription: "Some Error has happened")
Intuitively, I would expect a type like MYError
to just use an initializer MYError(domain:...
, not a static function.
The more Swifty way would be something like:
enum ErrorType: Error {
case one
case two
case three(with: String)
}
...
// In some function:
throw ErrorThrown.three(with: "Three!")
...
// Catch like:
catch ErrorType.three(let str) {
print("Error three: \(str)")
}
It is not clear if we're there yet. It seems that NSError is still much at play where I know I can expect to get a localizedDescription
an optional localizedFailureReason
and the familiar NSError properties.
Similarly as in How to provide a localized description with an Error type in Swift?
you can define a custom error type adopting the LocalizedError
protocol:
public struct MyError: Error {
let msg: String
}
extension MyError: LocalizedError {
public var errorDescription: String? {
return NSLocalizedString(msg, comment: "")
}
}
Example:
do {
throw MyError(msg: "Something happened")
} catch let error {
print(error.localizedDescription)
}
This prints the localized version of the given message.
Note that error
in the catch-clause is a general Error
, so
the caller does not need to cast it to the concrete error type (or even know
which error type is thrown).
Error
is a protocol, you can throw anything which conforms to that protocol
For example
struct MYError : Error {
let description : String
let domain : String
var localizedDescription: String {
return NSLocalizedString(description, comment: "")
}
}
And you can use it:
func test() throws
{
throw MYError(description: "Some Error has happened", domain: "com.somthing.error")
}
do {
try test()
} catch let error as MYError{
print("error: ", error.domain, error.localizedDescription)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With