objective-cswiftnserror

How to compare NSError.code to #defined error number in Swift 5


I have been working with Objective-C for a couple of years know but I am still quite new to Swift.

Currently I am working to add some new Swift 5 based code to an existing Objective-C project which uses defined constants for error codes and NSError objects to propagate errors.

How can I use NSError.code in Swift?

Obective-C code:

#define someStrangeError_Code   1000
typedef void(^CompletionHandler)(BOOL success, NSError *error);

...

- (void)doSomethingAsync:(CompletionHandler)completion {
    // ... do something

    if (errorOccured) {
        completion(false, [NSError errorWithDomain:@"MyErrorDomain" code:someStrangeError_Code userInfo:nil])
    } else {
        completion(true, nil)
    }

    ...
}    

[someObjc doSomethingAsync:^(BOOL success, NSError *error) {
    if (error != nil && error.code == someStrangeError_Code) {
        ....
    }
}];

Swift code:

someObjc.doSomethingAsync(completion: { (success, error) in 
    if ((error as NSError?)?.code == someStrangeError_Code) {
        // ERROR
        // Binary operator '==' cannot be applied to operands of type 'Int?' and 'Int32'
    }
})

I know that Swift uses the Error protocol instead of NSError. However, NSError complies to Error and thus using NSError should not be a problem, should it?

Comparing a simple error code to a constant should not be that hard, but I could not solve this.

So what is the correct "Swift way" to check the error code an to avoid

Binary operator '==' cannot be applied to operands of type 'Int?' and 'Int32'


Solution

  • C integers are imported to Swift as Int32, and that cannot be compared to an optional Int? directly. A conversion helps:

    if ((error as NSError?)?.code == Int(someStrangeError_Code)) {
        // some strange error
    }
    

    Alternatively, unwrap the optional error first:

    if let error = error {
        if (error as NSError).code == someStrangeError_Code {
            // some strange error
        } else {
            // some other error
        }
    } else {
        // no error
    }
    

    Yet another option is to change the (Objective-)C definition to

    #define someStrangeError_Code   1000L
    

    for a long int constant, which is imported to Swift as Int. Then your original Swift code would compile again.