Reputation: 21
NSSetUncaughtExceptionHandler catches only Objective-C exceptions. I need to catch only swift exceptions. Is it possible?
NSSetUncaughtExceptionHandler catches this one. let arr = NSArray() let x = arr[4]
I also want to catch this crash. let number: Int? = nil let val = number!
Upvotes: 1
Views: 253
Reputation: 20379
As I already mentioned in my comment above
Swift does not deal with exception, it deals with error, hence when you use try catch block of swift for let x = arr[4]
you cant catch the exceptions (Its array out of bound exception not an error).
As Vadian also pointed out Swift encourages you to catch and solve those exceptions rather than catching them at run time.
That being said, there might be scenarios when you have to deal with exceptions explicitly, example you are dealing with third party framework which is written in Objective-C and might throw an exception or you might be dealing with certain iOS API which still runs in Objective-C runtime and throws exception in such cases, its handy to have a have method of your own in objective C and pass swift statements to it using block / closure and execute them inside Objective-C try catch block,
How can you do it?
Add an Objective-C file to your swift project, it will ask you should it create bridging header as well, say yes, update your .h and .m files as shown
ExceptionCatcher.h
#import <Foundation/Foundation.h>
@interface ExceptionCatcher : NSObject
+ (void)catchExceptionIfAny: (void(^)(void)) executeCodeBlock withCompletion: (void (^)(NSException *)) completion;
@end
ExceptionCatcher.m
#import <Foundation/Foundation.h>
#import "ExceptionCatcher.h"
@implementation ExceptionCatcher : NSObject
+ (void)catchExceptionIfAny: (void(^)(void)) executeCodeBlock withCompletion: (void (^)(NSException *)) completion {
@try {
executeCodeBlock();
}
@catch (NSException *exception) {
NSLog(@"%@", exception.description);
completion(exception);
}
}
@end
Finally, update your bridging header file with
#import "ExceptionCatcher.h"
And come to swift file and use it as
let x = NSArray()
ExceptionCatcher.catchExceptionIfAny({[weak self] in
let a = x[4]
debugPrint(a)
}) { (exception) in
if let e = exception {
debugPrint(e.description)
}
}
As you can see obviously x[4] should end up with array out of bound exception, now instead of crashing exception will be captured and returned to your completion block.
The code above works because x is declared as NSArray
which is extended form NSObject
if you use x = [1,2,3]
you will be creating an instance of Swift Array and obviously swift array wont throw exception. So be very careful when you use this method.
This is not a work around to catch all sort of Exceptions
and should be used sparingly (only in cases when avoiding it is impossible) This is an overkill and unnecessary for this usecase however
Upvotes: 1