The following code in Swift raises NSInvalidArgumentException exception:
task = NSTask() task.launchPath = "/SomeWrongPath" task.launch()
How can I catch the exception? As I understand, try/catch in Swift is for errors thrown within Swift, not for NSExceptions raised from objects like NSTask (which I guess is written in ObjC). I'm new to Swift so may be I'm missing something obvious...
Edit: here's a radar for the bug (specifically for NSTask): openradar.appspot.com/22837476
An object that represents a special condition that interrupts the normal flow of program execution.
Handling Errors Using Do-Catch. You use a do - catch statement to handle errors by running a block of code. If an error is thrown by the code in the do clause, it's matched against the catch clauses to determine which one of them can handle the error.
The try/catch syntax was added in Swift 2.0 to make exception handling clearer and safer. It's made up of three parts: do starts a block of code that might fail, catch is where execution gets transferred if any errors occur, and any function calls that might fail need to be called using try .
do – This keyword starts the block of code that contains the method that can potentially throw an error. try – You must use this keyword in front of the method that throws. Think of it like this: “You're trying to execute the method.
Here is some code, that converts NSExceptions to Swift 2 errors.
Now you can use
do { try ObjC.catchException { /* calls that might throw an NSException */ } } catch { print("An error ocurred: \(error)") }
ObjC.h:
#import <Foundation/Foundation.h> @interface ObjC : NSObject + (BOOL)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error; @end
ObjC.m
#import "ObjC.h" @implementation ObjC + (BOOL)catchException:(void(^)(void))tryBlock error:(__autoreleasing NSError **)error { @try { tryBlock(); return YES; } @catch (NSException *exception) { *error = [[NSError alloc] initWithDomain:exception.name code:0 userInfo:exception.userInfo]; return NO; } } @end
Don't forget to add this to your "*-Bridging-Header.h":
#import "ObjC.h"
What I suggest is to make an C function that will catch the exception and return a NSError instead. And then, use this function.
The function could look like this:
NSError *tryCatch(void(^tryBlock)(), NSError *(^convertNSException)(NSException *)) { NSError *error = nil; @try { tryBlock(); } @catch (NSException *exception) { error = convertNSException(exception); } @finally { return error; } }
And with a little bridging help, you'll just have to call:
if let error = tryCatch(task.launch, myConvertFunction) { print("An exception happened!", error.localizedDescription) // Do stuff } // Continue task
Note: I didn't really test it, I couldn't find a quick and easy way to have Objective-C and Swift in a Playground.
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