我正在尝试从Swift访问用C ++标头编写的enum
值。具体来说,我在OpenCV的hpp头文件中有这个enum
我希望将其值暴露给Swift。我试图在Swift和Objective-C之间设置一个桥接头,并为我想要公开的C ++枚举值设置一个包装器,但是编译器并不高兴:
imgproc.hpp :C ++头文件
enum ThresholdTypes {
THRESH_BINARY = 0,
THRESH_BINARY_INV = 1,
THRESH_TRUNC = 2,
...
};
桥接标题:
#import "OpenCVWrapper.h"
OpenCVWrapper.h :我的Objective-C Wrapper类暴露给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
如果我将此枚举声明和C ++代码(OpenCV)导入到OpenCVWrapper.mm
,那么编译器就可以了,我也可以使用它,但是我想将这个枚举暴露给Swift所以它必须在头文件中。但是,当我直接在Objective-C头文件中公开C ++枚举时,有些事情是不正确的。
是否可以直接从Objective-C头部访问C ++常量/枚举,以便它可以桥接到Swift?
答案 0 :(得分:2)
OpenCV C ++库中定义的enum
值旨在与同一库中定义的API一起使用,并且需要将这些API包装起来以便在Swift中使用。包装器层还可以包含用于在C ++和Swift之间转换enum
的代码,以便更改C ++ enum
的值不会破坏Swift代码。这是可能的,因为包装器知道Swift和C ++ enum
值。
让我们说C ++头文件,称之为CPP.h
,有:
namespace cv {
enum ThresholdTypes {
THRESH_BINARY = 0,
THRESH_BINARY_INV = 111,
THRESH_TRUNC = 222
};
void useThreshold(ThresholdTypes t);
ThresholdTypes returnThreshold();
};
实施对我们的目的并不重要。在CPPWrapper.h
中,暴露给Swift的包装器API看起来像
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
这是包装器实现,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
以上代码段不是完整的源代码文件,但应该让您了解正在进行的操作。代码可以通过多种方式变得更加健壮,但这超出了简短答案的范围。
答案 1 :(得分:0)
你唯一能做的就是在你的.h文件中创建一个全新的,独立的枚举,它具有与C ++枚举相同的数值,然后在你的Objective-C ++文件中使用编译时断言(static_assert)来检查值是否相同。
typedef enum {
Binary = 7, // cv::THRESH_BINARY: use of undeclared identifier `cv`
BinaryInv = 12 // cv::THRESH_BINARY_INV: use of undeclared identifier `cv`
} ThresholdingType;
显然,输入正确的数字,无论它们是什么。并检查.mm文件,以防原始C ++标头更改。