如何在 Obj-C 中使用 C++ 静态库?

How do I use a C++ static library in Obj-C?

我有一个 C++ 静态库:.a 文件和 staticLibrary.h 文件。

在.h文件中,有一个class我要访问:

typedef enum
{
    eStaticLibOperationUnknown               = 0
    eStaticLibOperationSystemCheck           = 1
} enumStaticLibOperation;

typedef enum
{
    eStaticLibResultUnknown              = 0,
    eStaticLibResultNullParameter        = 4,
    eStaticLibResultWrongParameter       = 5
} enumStaticLibResult;

typedef std::function<void(void)> typeCallBack;

class classResultHelper
{
    blah blah
};

class staticLibrary
{
public:
      staticLibrary(typeCallBack, const char*);

      void requestOperation(const char*, size_t);
      void requestOperation(enumStaticLibOperation, const char*, size_t);
      enumStaticLibResult getResult(char**, size_t*);
};

我在 viewController.m 文件的顶部使用了 #import "staticLibrary.h"。这引发了一个错误,因为它认为 C++ 是外来的。然后我将 viewController 更改为 .mm 扩展名,使文件成为 Objective-C++ 并删除了错误。

但是当我尝试在 viewDidLoad 中 运行 staticLibrary* sL = [[staticLibrary alloc] init]; 时,我在右侧的第二个 staticLibrary 处出错。它说 "receiver type is not an objective-c class"。我做错了什么?

在查看使用静态库的文档时,它说:

1.1. new staticLibrary(callback, “en”);
1.2. requestOperation(“enumSystemcheck”, NULL, 0);
1.3. callback();
1.4. getResult(... , ...);"

我相信这是 Java (?),第一行是使用这些参数创建 staticLibrary 的实例。在 objective-C 中我该怎么做?

示例中的代码不是 Java,而是 C++。 ObjC++ 意味着你可以在一行中混合用 C++ 或 ObjC 编写的语句,这并不意味着你可以像使用 ObjC objects 一样使用 C++ objects,或者使用 ObjC 语法。

人们通常做的只是在 .mm 文件本身中包含 C++ headers 和编写 C++ 代码,而不会在 header 中放入任何内容。编写一个 ObjC class 来包装您想要的 C++ 库部分。所以在你的例子中,那会是这样的:

JCRStaticLibrary.h

@interface JCRStaticLibrary : NSObject
-(instancetype) initWithCallback: (void(^)(void))inObjCCallback;
-(void) requestOperation: (NSString*)what withBuffer: (void*)buf size: (int)theSize;
@end

JCRStaticLibrary.mm

#import "JCRStaticLibrary.h"
#include "staticLibrary.h"

@interface JCRStaticLibrary ()
{
    staticLibrary *_cppStaticLibrary;
}
@end

@implementation JCRStaticLibrary

-(instancetype) initWithCallback: (void(^)(void))inObjCCallback
{
    self = [super init];
    if( self )
    {
        _staticLibrary = new staticLibrary( inObjCCallback, "en"); // ObjC++ knows how to turn an ObjC block into a C++ lambda.
        // Under the hood it generates code like:
        // _staticLibrary = new staticLibrary( [inObjCCallback](){ inObjCCallback(); }, "en");
        // Where the [inObjCCallback](){} part is how C++ does lambdas, its equivalent to blocks.
        // I.e. it's roughly analogous to ObjC's ^(){}.
    }
}

-(void) dealloc
{
    delete _staticLibrary;
}

-(void) requestOperation: (NSString*)what withBuffer: (void*)buf size: (int)theSize
{
    _staticLibrary->requestOperation( [what UTF8String], buf, theSize );
}

@end

类似的东西。我不知道你的情况下 requestOperation 的参数实际上是什么,所以我只是做了一个有根据的猜测。

除了将 ObjC 块传递给 -initWithCallback:,您还可以编写自己的 lambda 并将其作为方法,即:

-(instancetype) init
{
    __weak JCRStaticLibrary *weakSelf = self; // Avoid retain circle.
    _staticLibrary = new staticLibrary( [weakSelf](){ [weakSelf doCallbackThing]; }, "en"); // ObjC++ knows how to turn an ObjC block into a C++ lambda.
}

-(void) doCallbackThing
{
    // Do whatever the callback should do here.
}

这实际上取决于每次创建此类型的 object 时回调是否更改(例如,如果 JCRStaticLibrary object 表示通过网络发送的命令)或来自一个小集合一遍又一遍地使用的命令(例如,您收到一个视频帧并对其应用过滤器,然后将其交给另一个 object,因此您实际上只有一个回调)。在前一种情况下你想保留块,在后者中,每个过滤器 有一个 subclass 可能 更有意义(除非你想在过滤器之间切换 on-the-fly).