Created
May 30, 2022 13:51
-
-
Save gcbrueckmann/867a1b45a5417355add7868c6b46276a to your computer and use it in GitHub Desktop.
Converting Objective-C exceptions to Swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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