I have a situation where I'm trying to override NSError
to provide me an instance of an error I'm going to be re-using a lot.
My code was working until I updated Xcode and converted to Swift 2.
public class NAUnexpectedResponseTypeError: NSError {
public convenience init() {
let messasge = "The object fetched by AFNetworking was not of an expected type."
self.init(
domain: "MyDomain",
code: 6782,
userInfo: [NSLocalizedDescriptionKey: messasge]
)
}
}
The compiler says Cannot override 'init' which has been marked unavailable
. I was able to hack around it by doing this:
public class NAUnexpectedResponseTypeError: NSError {
public class func error() -> NSError {
let message = "The object fetched by AFNetworking was not of an expected type."
return NAUnexpectedResponseTypeError(
domain: "MyDomain",
code: 6782,
userInfo: [NSLocalizedDescriptionKey: message]
)
}
}
So, my question is:
init
method in a situation like this?EDIT:
I came up with another workaround that I like better than the workaround with the class method. I'm still not happy that I can't override the empty init
method though.
public class NAUnexpectedResponseTypeError: NSError {
public convenience init(message: String?) {
var errorMessage: String
if let message = message {
errorMessage = message
} else {
errorMessage = "The object fetched by AFNetworking was not of an expected type."
}
self.init(
domain: "MyDomain",
code: 6782,
userInfo: [NSLocalizedDescriptionKey: errorMessage]
)
}
}
Since NSError
is immutable, there's no reason to create multiple instances of the same data. Just create a single, constant, instance:
let NAUnexpectedResponseTypeError = NSError(domain: "MyDomain",
code: 6782,
userInfo: [NSLocalizedDescriptionKey: "The object fetched by AFNetworking was not of an expected type."]
)
If you have a situation that isn't constant, then it is almost always better to extend rather than subclass NSError
. For example:
extension NSError {
class func MyError(code code:code, message: String) -> NSError {
return NSError(domain: "MyDomain",
code: code,
userInfo: [NSLocalizedDescriptionKey: message])
}
}
This kind of extension (as a category) has a long history in ObjC, and is a good pattern to bring to Swift (if you can't easily use enum
ErrorTypes, which are even better Swift).
In many cases I find it even easier just to have a top-level function for this, rather than extending NSError
. For example:
private func makeError(code code:code, message: String) -> NSError {
return NSError(domain: "MyDomain",
code: code,
userInfo: [NSLocalizedDescriptionKey: message])
}
(Personally I use these kinds of functions all the time in Swift when I have to use NSError
. In ObjC, I typically used categories on NSError
. Not sure why I changed, but it feels more natural.)
You can't override the empty init, it's marked as unavailable so you're not supposed to be able to do anything with it.
You do have another workaround though
public class NAUnexpectedResponseTypeError: NSError {
public convenience init(message: String = "The object fetched by AFNetworking was not of an expected type.") {
self.init(
domain: "MyDomain",
code: 6782,
userInfo: [NSLocalizedDescriptionKey: message]
)
}
}
I didn't test it, but it should work.
Since you're using swift 2.0, why don't you make your instance conform to error type instead of subclassing NSError ? It would be cleaner and more idiomatic.
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