robdashnash robdashnash - 6 months ago 27
Swift Question

Swift: Should NSError now be considered as legacy?

The docs and popular blogs suggest Swift error handling be done with do-catch and to handle an ErrorType enum or an NSError instance.

Are ErrorType enum and NSError instances mutually exclusive in a try catch block? If not, how do you implement a function that throws both?

I have associated an NSError instance to an enum like so, which seems to work, but is this the de facto way of returning detailed error information?

enum Length : ErrorType {
case NotLongEnough(NSError)
case TooLong(NSError)
}

func myFunction() throws {
throw Length.NotLongEnough(NSError(domain: "domain", code: 0, userInfo: [NSLocalizedFailureReasonErrorKey: "Not long enough mate"]))
}

do {
try myFunction()
} catch MyError.RuntimeError(let error) {
print("\(error)")
}


This example shows how ErrorType can be cast to NSError.

do {
let str = try NSString(contentsOfFile: "Foo.bar",
encoding: NSUTF8StringEncoding)
}
catch let error as NSError {
print(error.localizedDescription)
}


I can't find an error enum that conforms to ErrorType for NSString so should we assume it will be an NSError instance ? Granted we could run the code to be sure, but surely the docs should let us know. (I appreciate I might have mis-read the docs)

Answer

NSError class adopts ErrorType interface and any ErrorType-conformant class can be casted to NSError. These features are described here in the docs.

You can safely stick to ErrorType, especially if you're planning to interoperate with Swift only.

enum CommonError: ErrorType {
    case InternalInconsistency(String)
}

func boom() throws {
    throw CommonError.InternalInconsistency("Boom!")
}

do {
    try boom()
} catch {
    print(error) // InternalInconsistency("Boom!")
    print(error as NSError) // Error Domain=CommonError Code=0 "(null)"
}

do {
    try boom()
} catch let CommonError.InternalInconsistency(msg) {
    print("Error: \(msg)") // Error: Boom!
}
Comments