C++中调用OC代码

126 篇文章 2 订阅
9 篇文章 0 订阅

前言

  最近项目中为了方便维护,底层统一使用C++编写。由于是项目是做屏幕共享sdk,所以只能底层的压缩、编解码使用C++,屏幕捕获部分Mac和win就自己实现了。那么问题就来了,因为是面向接口编程,所以项目的入口都是c++来写的,而屏幕捕获是需要oc部分的代码,就需要C++调用oc代码了。

准备

之前只做过OC调动C++,于是Google了一下,在Stack Overflow上找到了这个回答。要看具体描述的可以去链接看看,实现思路一共有两种,我在这里大概描述一下。第一种,由于C++是不能直接调用OC的,所以需要通过C语言作为中间层,即C++调用C,C调用OC,这样就达到了C++调用OC的目的。第二种OC是可以调用C++的,通过在外部声名C++类,然后类具体实现放在OC类中,这样C++类就能够调用OC类了,其他需要调用OC的类,只需要调用外部声名的类即可。

实现

具体的实现方式有两种,第一种是C语言方法接收oc对象指针和参数,然后把指针桥接为具体的oc对象。第二种是用C++进行包装,先声名一个C++类,这里称为A。然后在OC类中,这里称为B,对A进行实现,因为这个实现实在OC语言里的,所以在这里是可以直接调用OC代码的。接下来声名一个C++类C。类C通过持有类A来调用OC类B,即A(C++)->C(C++)->B(OC类)

实现方式一 by C

MyObject-C-Interface.h

int MyObjectDoSomethingWith (void *myObjectInstance, void *parameter);

MyObject.h

 
  1. @interface MyObject : NSObject

  2. {

  3. int someVar;

  4. }

  5. - (int)doSomethingWith:(void *)aParameter;

  6. @end

MyObject.mm

 
  1. @implementation MyObject

  2. int MyObjectDoSomethingWith (void *self, void *aParameter)

  3. {

  4. // 通过将self指针桥接为oc 对象来调用oc方法

  5. return [(__bridge id)self doSomethingWith:aParameter];

  6. }

  7. - (int) doSomethingWith:(void *) aParameter

  8. {

  9. //将void *指针强转为对应的类型

  10. int* param = (int *)aParameter;

  11. return *param / 2 ;

  12. }

  13. - (void)dealloc

  14. {

  15. NSLog(@"%s", __func__);

  16. }

  17. @end

MyCPPClass.h

 
  1. class MyCPPClass {

  2. public:

  3. MyCPPClass();

  4. ~MyCPPClass();

  5. int someMethod (void *objectiveCObject, void *aParameter);

  6. void *self;

  7. void setSelf(void *self);

  8. };

MyCPPClass.cpp

 
  1. #include "MyObject-C-Interface.h"

  2. MyCPPClass::MyCPPClass()

  3. {

  4. }

  5. MyCPPClass::~MyCPPClass()

  6. {

  7. }

  8. int MyCPPClass::someMethod (void *objectiveCObject, void *aParameter)

  9. {

  10. // To invoke an Objective-C method from C++, use

  11. // the C trampoline function

  12. return MyObjectDoSomethingWith (objectiveCObject, aParameter);

  13. }

  14. void MyCPPClass::setSelf(void *aSelf)

  15. {

  16. self = aSelf;

  17. }

main.mm

 
  1. #include "MyCPPClass.hpp"

  2. #import "MyObject.h"

  3. int main(int argc, const char * argv[]) {

  4. @autoreleasepool {

  5. // insert code here...

  6. NSLog(@"Hello, World!");

  7. MyObject *object = [[MyObject alloc] init];

  8. MyCPPClass *c = new MyCPPClass();

  9. c->setSelf((__bridge void *)object);

  10. int a = 12;

  11. int result = c->someMethod((__bridge void *)object, &a);

  12. NSLog(@"%d", result);

  13. }

  14. return 0;

  15. }

运行结果如下:

存在的问题

在每次C++调用时都需要传递OC对象桥接为==void *==的指针,使用起来很不方便。

方式二 by C++ IMPL

MyObject-C-Interface.h

 
  1. #ifndef MyObject_C_Interface_h__h

  2. #define MyObject_C_Interface_h__h

  3. class MyClassImpl

  4. {

  5. public:

  6. MyClassImpl ( void );

  7. ~MyClassImpl( void );

  8. void init( void );

  9. int doSomethingWith( void * aParameter );

  10. void logMyMessage( char * aCStr );

  11. private:

  12. void * self;

  13. };

  14. #endif /* MyObject_C_Interface_h__h */

需要注意的是,==MyClassImpl==的实现是放在OC中的
MyObject.h

 
  1. NS_ASSUME_NONNULL_BEGIN

  2. @interface MyObject : NSObject

  3. {

  4. int someVar;

  5. }

  6. - (int) doSomethingWith:(void *) aParameter;

  7. - (void) logMyMessage:(char *) aCStr;

  8. @end

  9. NS_ASSUME_NONNULL_END

MyObject.mm

 
  1. #include "MyObject-C-Interface.h"

  2. typedef void(^RetainSelfBlock)(void);

  3. @implementation MyObject

  4. {

  5. RetainSelfBlock _retainBlock;//通过这个block持有对象,造成循环引用,避免被释放

  6. }

  7. MyClassImpl::MyClassImpl( void )

  8. : self( NULL )

  9. {

  10. }

  11. MyClassImpl::~MyClassImpl( void )

  12. {

  13. [(__bridge id) self breakRetainCycly];

  14. }

  15. void MyClassImpl::init( void )

  16. {

  17. MyObject *object = [[MyObject alloc] init];

  18. object->_retainBlock = ^{//循环引用

  19. [object class];

  20. };

  21. self = (__bridge void *)object;

  22. NSLog(@"%p", self);

  23. }

  24. int MyClassImpl::doSomethingWith( void *aParameter )

  25. {

  26. NSLog(@"%p", self);

  27. return [(__bridge id)self doSomethingWith:aParameter];

  28. }

  29. void MyClassImpl::logMyMessage( char *aCStr )

  30. {

  31. [(__bridge id)self logMyMessage:aCStr];

  32. }

  33. - (int) doSomethingWith:(void *) aParameter

  34. {

  35. int result = 0;

  36. // ... some code to calculate the result

  37. return result;

  38. }

  39. - (void) logMyMessage:(char *) aCStr

  40. {

  41. NSLog( @"%s", aCStr );

  42. }

  43. //打破循环引用,释放对象

  44. - (void) breakRetainCycly

  45. {

  46. _retainBlock = nil;

  47. }

  48. - (void)dealloc

  49. {

  50. NSLog(@"%s", __func__);

  51. }

  52. @end

在==MyObject.mm==中需要注意的是,由于OC是使用ARC来进行内存管理的,C++不能够管理OC对象的生命周期。在默认的情况下,临时变量会在autorelease pool每一次pop后被释放,所以在oc实现中要想对象不被释放,那就需要循环引用来帮忙了。

具体代码如下,在MyClassImpl初始化时,利用循环引用保证object不被释放,在MyClassImpl调用析构函数时,将block置空,打破循环引用,以此来释放oc对象

 
  1. void MyClassImpl::init( void )

  2. {

  3. MyObject *object = [[MyObject alloc] init];

  4. object->_retainBlock = ^{//循环引用

  5. [object class];

  6. };

  7. self = (__bridge void *)object;

  8. NSLog(@"%p", self);

  9. }

  10. MyClassImpl::~MyClassImpl( void )

  11. {

  12. [(__bridge id) self breakRetainCycly];

  13. }

  14. //打破循环引用,释放对象

  15. - (void) breakRetainCycly

  16. {

  17. _retainBlock = nil;

  18. }

MyCPPClass.hpp

 
  1. #ifndef MyCPPClass_hpp

  2. #define MyCPPClass_hpp

  3. #include <stdio.h>

  4. class MyClassImpl;

  5. class MyCPPClass

  6. {

  7. enum { cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42 };

  8. public:

  9. MyCPPClass ( void );

  10. ~MyCPPClass( void );

  11. void init( void );

  12. void doSomethingWithMyClass( void );

  13. private:

  14. MyClassImpl * _impl;

  15. int _myValue;

  16. };

  17. #endif /* MyCPPClass_hpp */

MyCPPClass.cpp

 
  1. #include "MyCPPClass.hpp"

  2. #include "MyObject-C-Interface.h"

  3. MyCPPClass::MyCPPClass( void )

  4. : _impl ( NULL )

  5. { }

  6. void MyCPPClass::init( void )

  7. {

  8. _impl = new MyClassImpl();

  9. _impl->init();

  10. }

  11. MyCPPClass::~MyCPPClass( void )

  12. {

  13. if ( _impl ) { delete _impl; _impl = NULL; }

  14. }

  15. void MyCPPClass::doSomethingWithMyClass( void )

  16. {

  17. int result = _impl->doSomethingWith(&_myValue);

  18. if ( result == cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING )

  19. {

  20. _impl->logMyMessage("Hello, Arthur!");

  21. }

  22. else

  23. {

  24. _impl->logMyMessage("Don't worry.");

  25. }

  26. }

main.mm

 
  1. #include "MyCPPClass.hpp"

  2. int main(int argc, const char * argv[]) {

  3. @autoreleasepool {

  4. MyCPPClass *temp = new MyCPPClass();

  5. temp->init();

  6. temp->doSomethingWithMyClass();

  7. delete temp;

  8. }

  9. return 0;

  10. }

运行结果

总结

第一种通过C语言的方式来调用,使用起来更复杂,所以建议使用C++的方式来实现。需要注意的问题是C++不能管理OC对象的释放,所以需要利用循环引用。

你可以在这里下载demo

参考:Calling Objective-C method from C++ member function? - Stack Overflow

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值