Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save gcbrueckmann/867a1b45a5417355add7868c6b46276a to your computer and use it in GitHub Desktop.
Save gcbrueckmann/867a1b45a5417355add7868c6b46276a to your computer and use it in GitHub Desktop.
Converting Objective-C exceptions to Swift
@import Foundation;
NS_ASSUME_NONNULL_BEGIN
extern NSString *const GCBConvertedObjCExceptionErrorDomain;
extern NSString *const GCBConvertedObjCExceptionUserInfoExceptionKey;
typedef NS_CLOSED_ENUM(NSInteger, GCBConvertedObjCExceptionErrorCode)
{
GCBConvertedObjCExceptionErrorCodeCaughtException = 1
};
@interface NSException (GCBSwiftErrorConversion)
/// Helper method used by the @c withExceptionsRethrownAsErrors(_:) Swift function.
/// Prefer that one over calling this directly.
+ (BOOL)performAndConvertExceptions:(void (^)(void))block error:(NSError **)outError NS_REFINED_FOR_SWIFT;
@end
NS_ASSUME_NONNULL_END
#import "NSException+GCBSwiftErrorConversion.h"
NSString *const GCBConvertedObjCExceptionErrorDomain = @"de.gcbrueckmann.ConvertedObjCException";
NSString *const GCBConvertedObjCExceptionUserInfoExceptionKey = @"exception";
@implementation NSException (GCBSwiftErrorConversion)
+ (BOOL)performAndConvertExceptions:(void (^)(void))block error:(NSError **)outError {
@try {
block();
return YES;
} @catch (NSException *exception) {
NSDictionary *userInfo = @{ GCBConvertedObjCExceptionUserInfoExceptionKey: exception };
if (outError) *outError = [NSError errorWithDomain:GCBConvertedObjCExceptionErrorDomain code:GCBConvertedObjCExceptionErrorCodeCaughtException userInfo:userInfo];
return NO;
}
}
@end
import Foundation
/// Executes a closure and catches any Objective-C exceptions raised from it.
/// Caught exceptions are re-thrown as errors of type `ObjCExceptionError`.
///
/// **Example:**
///
/// do {
/// try withExceptionsRethrownAsErrors {
/// tableFlipper.flipTheTable()
/// }
/// } catch is ObjCExceptionError {
/// // Handle exception here
/// }
func withExceptionsRethrownAsErrors<Result>(_ body: () -> Result) throws -> Result {
do {
return try withoutActuallyEscaping(body) { escapableBody in
var result: Result!
try NSException.__performAndConvertExceptions {
result = escapableBody()
}
return result
}
} catch let error as NSError where error.domain == GCBConvertedObjCExceptionErrorDomain {
guard let exception = error.userInfo[GCBConvertedObjCExceptionUserInfoExceptionKey] as? NSException else {
preconditionFailure()
}
throw ObjCExceptionError(exception: exception)
}
}
struct ObjCExceptionError: Error {
let exception: NSException
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment