Swift, iOS and C++ exceptions

Hi,

I am creating an example app to demonstrate the integration of our text to speech (university research) C++ api.

This app is specifically for iOS using swift/swiftui.

The C++ api makes use of exceptions when things are not as it wants it - yep, it basically sits down and sulks !

At this stage, I cannot change that.

My research has done no more than confuse me as to if I can catch any C++ exception from within swift.

I am not interested in backtraces, just being able to access the reason for the exception (std::exception.what()).

Can this be done ? If so, how, please ?

Can this be done ?

NO.

You may need to write some Objective-C++ code to interface your C++ apis to swift.

To elaborate on OOPer’s response, C++ and Objective-C share an exception model [1]. Objective-C code can catch exceptions thrown by C++ and vice versa. Swift does not use that exception model. Rather, the Swit constructs that look like exceptions (throw, catch, and so on) are actually built on top of something that’s more akin to Objective-C’s error model (NSError). Swift has no support for the exceptions used by the other languages.

Having said that, this is unlikely to cause you problems because you can’t call C++ directly from Swift anyway (maybe one day!). The easiest way to get from Swift to C++ is to write an Objective-C++ wrapper. It can:

  • Call the C++ directly

  • Catch any C++ exceptions

  • Publish an Objective-C interface that Swift can call

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] On modern platforms. On 32-bit Intel this wasn’t the case.

Hi Quinn,

Thank you for your, expanded, explanation.

As I have never done any objective-c or objective-c++, are you able to point me to some examples which will help me write this wrapper, please ?

Oh, goodness, Objective-C++ is a bit of a dark art (-: The language itself is pretty obvious: You subtract C from Objective-C to get the ‘Objective-’ bits, and then you add those to C++. However, there’s a bunch of subtlety here and it’s not something that I’ve used a lot.

OK, so, let’s see if I can create an example, but only if you forgive my terribly C++ (-:

Start with a C++ class like this:

---------------------------------------------------------------------------
// CPPTest.hpp

#ifndef CPPTest_hpp
#define CPPTest_hpp

class CPPTest {
public:
    CPPTest();
    ~CPPTest();
    void test();
};

#endif /* CPPTest_hpp */
---------------------------------------------------------------------------
// CPPTest.cpp

#include "CPPTest.hpp"

#include "stdio.h"

CPPTest::CPPTest() {
    printf("construct\n");
}

CPPTest::~CPPTest() {
    printf("destruct\n");
}

void CPPTest::test() {
    printf("Hello Cruel World!\n");
}
---------------------------------------------------------------------------

Note You can tell I’m scared of C++ because I’m using the C stdio library here (-:

Wrap that in an Objective-C++ class like this:

---------------------------------------------------------------------------
// OCPPTest.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface OCPPTest : NSObject

- (instancetype)init;

- (void)test;

@end

NS_ASSUME_NONNULL_END
---------------------------------------------------------------------------
// OCPPTest.mm

#import "OCPPTest.h"

#include <stdio.h>

#include "CPPTest.hpp"

@implementation OCPPTest {
    CPPTest * _cppTest;
}

- (instancetype)init {
    printf("init\n");
    self = [super init];
    if (self != nil) {
        self->_cppTest = new CPPTest();
    }
    return self;
}

- (void)dealloc {
    printf("dealloc\n");
    delete self->_cppTest;
}

- (void)test {
    self->_cppTest->test();
}

@end
---------------------------------------------------------------------------

Then import that class into your Swift bridging header:

---------------------------------------------------------------------------
// OCPPMadness-Bridging-Header.h

#import "OCPPTest.h"
---------------------------------------------------------------------------

Finally, call it from Swift:

---------------------------------------------------------------------------
// main.swift

func main() {
    let o = OCPPTest()
    o.test()
}

main()
---------------------------------------------------------------------------

I tested this with a command-line tool project in Xcode 12.5. When I ran the tool it prints:

init
construct
Hello Cruel World!
dealloc
destruct

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi Quinn,

Thank you for all your (painfull) efforts ;-) I have managed to write the wrapper and catch exceptions correctly. Great work, thanks

Swift, iOS and C++ exceptions
 
 
Q