Using the NSUnderlyingError pattern caused an unexpected crash for me.
In Swift I had defined an Error like this:
@objc
public class WrappingError: NSObject, CustomNSError {
public let someDetails: String
public let someMoreDetails: UInt32
@objc
public static let kSomeDetailsKey = "kSomeDetailsKey"
@objc
public static let kSomeMoreDetailsKey = "kSomeMoreDetailsKey"
public let underlyingError: Error
init(someDetails: String, someMoreDetails: UInt32, underlyingError: Error) {
self.someDetails = someDetails
self.someMoreDetails = someMoreDetails
self.underlyingError = underlyingError
}
public var errorUserInfo: [String: Any] {
return [
type(of: self).someDetailsKey: someDetails,
type(of: self).someMoreDetailsKey: someMoreDetails,
NSUnderlyingErrorKey: underlyingError
]
}
}
The crash occurred in objc in some code like this:
NSError *error;
[SomeSwiftClass methodThatThrowsAWrappingError:&error]
if ([error.domain isEqualTo:@"MyModule.WrappingError"]) {
NSError *underlyingError = error.userInfo[NSUnderlyingErrorKey];
// !!! "unknown selector" crash on next line, because `underlyingError`
// is a Swift Error value, not an NSError
if ([underlyingError.domain isEqualTo:@"FooError"]) {
[self handleFooError];
}
}
Am I correct in concluding that the conversion from a Swift Error to an NSError occurs as part of the throwing process, and thus if I want to do something like the above, the right thing would be to make a change to WrappingError like:
public var errorUserInfo: [String: Any] {
return [
type(of: self).someDetailsKey: someDetails,
type(of: self).someMoreDetailsKey: someMoreDetails,
NSUnderlyingErrorKey: (underlyingError as NSError) // <- explicit cast
]
}