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

时间:2016-10-20 11:49:22

标签: objective-c static-libraries wrapper objective-c++

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

在.h文件中,有一个我想要访问的类:

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];时,我在右侧的第二个静态库中出现错误。它说&#34;接收器类型不是一个客观的c类&#34;。我做错了什么?

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

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

我相信这是Java(?),第一行是用这些参数创建一个staticLibrary实例。我如何在Objective-C中做到这一点?

1 个答案:

答案 0 :(得分:2)

示例中的代码不是Java,而是C ++。 ObjC ++意味着您可以在一行中混合使用C ++或ObjC创建的语句,这并不意味着您可以像使用ObjC对象一样使用C ++对象,也不能使用ObjC语法。

人们通常只会在.mm文件本身中包含C ++标头和编写C ++代码,而不是在标题中添加任何内容。编写一个ObjC类,它包装了你想要的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的参数究竟是什么,所以我只是做了一个有根据的猜测。

您可以编写自己的lambda并使其成为一种方法,而不是将ObjC块传递给-initWithCallback:,而不是:

-(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.
}

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