I am trying to access enum
's values written in C++ header from Swift. Specifically, I have this enum
in OpenCV's hpp header file that I would like to expose its values to Swift. I have attempted to set up a bridging header between Swift and Objective-C, and put a wrapper around C++ enum values I would like to expose, but the compiler isn't happy about it:
imgproc.hpp: The C++ header file
enum ThresholdTypes {
THRESH_BINARY = 0,
THRESH_BINARY_INV = 1,
THRESH_TRUNC = 2,
...
};
bridging header:
#import "OpenCVWrapper.h"
OpenCVWrapper.h: My Objective-C Wrapper class to be exposed to Swift
#ifdef __cplusplus
#import <opencv2/core.hpp>
#import <opencv2/imgproc.hpp>
#endif
#import <Foundation/Foundation.h>
@interface OpenCVWrapper : NSObject
typedef enum {
Binary = cv::THRESH_BINARY, // ERROR: use of undeclared identifier `cv`
BinaryInv = cv::THRESH_BINARY_INV // ERROR: use of undeclared identifier `cv`
} ThresholdingType;
...
@end
If I move this enum declaration and C++ code (OpenCV) import into OpenCVWrapper.mm
then the compiler is ok with it, and I can also use it just fine, but I want to expose this enum to Swift so it has to be in the header file. However, something is not right when I expose the C++ enum directly in Objective-C header.
Is it possible to access C++ constants / enums directly from Objective-C header, in such a way that it can be bridge to Swift?
I have looked at using extern like this and this but the C++ constants are still not recognized in my setup.
The enum
values defined in OpenCV C++ library are intended to be used with APIs defined in the same library, and those APIs will need to be wrapped for use in Swift. The wrapper layer can also include code for translating between enum
s in C++ and Swift in such a way that changing values of C++ enum
s won't break Swift code. This is possible because the wrapper knows about both Swift and C++ enum
values.
Let's say the C++ header file, call it CPP.h
, has:
namespace cv {
enum ThresholdTypes {
THRESH_BINARY = 0,
THRESH_BINARY_INV = 111,
THRESH_TRUNC = 222
};
void useThreshold(ThresholdTypes t);
ThresholdTypes returnThreshold();
};
The implementation is not important for our purposes. The wrapper API, in CPPWrapper.h
, exposed to Swift can look like
typedef enum {
THRESH_BINARY,
THRESH_BINARY_INV,
THRESH_TRUNC,
THRESH_UNKNOWN
} ThresholdTypesWrapper;
@interface CPPWrapper : NSObject
// The wrapper API operates in terms of wrapper `enum` values only.
// Translation between these and C++ `enum`s happens in the wrapper
// implementation.
+(void)useThreshold: (ThresholdTypesWrapper)thresholdType;
+(ThresholdTypesWrapper)returnThreshold;
@end
And here is the wrapper implementation, CPPWrapper.mm
:
cv::ThresholdTypes thresholdWrapped2Native(ThresholdTypesWrapper t) {
if (t==THRESH_BINARY) return cv::THRESH_BINARY;
else if (t==THRESH_BINARY_INV) return cv::THRESH_BINARY_INV;
else if (t==THRESH_TRUNC) return cv::THRESH_TRUNC;
// This should be very unlikely.
else throw std::runtime_error("Unknown threshold value detected.");
}
ThresholdTypesWrapper thresholdNative2Wrapped(cv::ThresholdTypes t) {
if (t==cv::THRESH_BINARY) return THRESH_BINARY;
else if (t==cv::THRESH_BINARY_INV) return THRESH_BINARY_INV;
else if (t==cv::THRESH_TRUNC) return THRESH_TRUNC;
// We could throw instead, but returning unknown is more forgiving if
// a new C++ enum value is added.
else return THRESH_UNKNOWN;
}
@implementation CPPWrapper
+(void)useThreshold: (ThresholdTypesWrapper)thresholdType {
cv::useThreshold(thresholdWrapped2Native(thresholdType));
}
+(ThresholdTypesWrapper)returnThreshold {
return thresholdNative2Wrapped(cv::returnThreshold());
}
@end
The above code snippets are not complete source code files, but should give you an idea of what's going on. The code could be made more robust in a number of ways, but that's beyond the scope of a short answer.
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