最近項目中爲了方便維護,底層統一使用C++編寫。因爲是項目是作屏幕共享sdk,因此只能底層的壓縮、編解碼使用C++,屏幕捕獲部分Mac和win就本身實現了。那麼問題就來了,由於是面向接口編程,因此項目的入口都是c++來寫的,而屏幕捕獲是須要oc部分的代碼,就須要C++調用oc代碼了。c++
以前只作過OC調動C++,因而Google了一下,在Stack Overflow上找到了這個回答。要看具體描述的能夠去連接看看,實現思路一共有兩種,我在這裏大概描述一下。第一種,因爲C++是不能直接調用OC的,因此須要經過C語言做爲中間層,即C++調用C,C調用OC,這樣就達到了C++調用OC的目的。第二種OC是能夠調用C++的,經過在外部聲名C++類,而後類具體實現放在OC類中,這樣C++類就可以調用OC類了,其餘須要調用OC的類,只須要調用外部聲名的類便可。git
具體的實現方式有兩種,第一種是C語言方法接收oc對象指針和參數,而後把指針橋接爲具體的oc對象。第二種是用C++進行包裝,先聲名一個C++類,這裏稱爲A。而後在OC類中,這裏稱爲B,對A進行實現,由於這個實現實在OC語言裏的,因此在這裏是能夠直接調用OC代碼的。接下來聲名一個C++類C。類C經過持有類A來調用OC類B,即A(C++)->C(C++)->B(OC類)github
MyObject-C-Interface.hobjective-c
int MyObjectDoSomethingWith (void *myObjectInstance, void *parameter);
MyObject.h編程
@interface MyObject : NSObject { int someVar; } - (int)doSomethingWith:(void *)aParameter; @end
MyObject.mm函數
@implementation MyObject int MyObjectDoSomethingWith (void *self, void *aParameter) { // 經過將self指針橋接爲oc 對象來調用oc方法 return [(__bridge id)self doSomethingWith:aParameter]; } - (int) doSomethingWith:(void *) aParameter { //將void *指針強轉爲對應的類型 int* param = (int *)aParameter; return *param / 2 ; } - (void)dealloc { NSLog(@"%s", __func__); } @end
MyCPPClass.h指針
class MyCPPClass { public: MyCPPClass(); ~MyCPPClass(); int someMethod (void *objectiveCObject, void *aParameter); void *self; void setSelf(void *self); };
MyCPPClass.cppcode
#include "MyObject-C-Interface.h" MyCPPClass::MyCPPClass() { } MyCPPClass::~MyCPPClass() { } int MyCPPClass::someMethod (void *objectiveCObject, void *aParameter) { // To invoke an Objective-C method from C++, use // the C trampoline function return MyObjectDoSomethingWith (objectiveCObject, aParameter); } void MyCPPClass::setSelf(void *aSelf) { self = aSelf; }
main.mm對象
#include "MyCPPClass.hpp" #import "MyObject.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); MyObject *object = [[MyObject alloc] init]; MyCPPClass *c = new MyCPPClass(); c->setSelf((__bridge void *)object); int a = 12; int result = c->someMethod((__bridge void *)object, &a); NSLog(@"%d", result); } return 0; }
運行結果以下:
blog
存在的問題
在每次C++調用時都須要傳遞OC對象橋接爲==void *==的指針,使用起來很不方便。
MyObject-C-Interface.h
#ifndef MyObject_C_Interface_h__h #define MyObject_C_Interface_h__h class MyClassImpl { public: MyClassImpl ( void ); ~MyClassImpl( void ); void init( void ); int doSomethingWith( void * aParameter ); void logMyMessage( char * aCStr ); private: void * self; }; #endif /* MyObject_C_Interface_h__h */
須要注意的是,==MyClassImpl==的實現是放在OC中的
MyObject.h
NS_ASSUME_NONNULL_BEGIN @interface MyObject : NSObject { int someVar; } - (int) doSomethingWith:(void *) aParameter; - (void) logMyMessage:(char *) aCStr; @end NS_ASSUME_NONNULL_END
MyObject.mm
#include "MyObject-C-Interface.h" typedef void(^RetainSelfBlock)(void); @implementation MyObject { RetainSelfBlock _retainBlock;//經過這個block持有對象,形成循環引用,避免被釋放 } MyClassImpl::MyClassImpl( void ) : self( NULL ) { } MyClassImpl::~MyClassImpl( void ) { [(__bridge id) self breakRetainCycly]; } void MyClassImpl::init( void ) { MyObject *object = [[MyObject alloc] init]; object->_retainBlock = ^{//循環引用 [object class]; }; self = (__bridge void *)object; NSLog(@"%p", self); } int MyClassImpl::doSomethingWith( void *aParameter ) { NSLog(@"%p", self); return [(__bridge id)self doSomethingWith:aParameter]; } void MyClassImpl::logMyMessage( char *aCStr ) { [(__bridge id)self logMyMessage:aCStr]; } - (int) doSomethingWith:(void *) aParameter { int result = 0; // ... some code to calculate the result return result; } - (void) logMyMessage:(char *) aCStr { NSLog( @"%s", aCStr ); } //打破循環引用,釋放對象 - (void) breakRetainCycly { _retainBlock = nil; } - (void)dealloc { NSLog(@"%s", __func__); } @end
在==MyObject.mm==中須要注意的是,因爲OC是使用ARC來進行內存管理的,C++不可以管理OC對象的生命週期。在默認的狀況下,臨時變量會在autorelease pool每一次pop後被釋放,因此在oc實現中要想對象不被釋放,那就須要循環引用來幫忙了。
具體代碼以下,在MyClassImpl初始化時,利用循環引用保證object不被釋放,在MyClassImpl調用析構函數時,將block置空,打破循環引用,以此來釋放oc對象
void MyClassImpl::init( void ) { MyObject *object = [[MyObject alloc] init]; object->_retainBlock = ^{//循環引用 [object class]; }; self = (__bridge void *)object; NSLog(@"%p", self); } MyClassImpl::~MyClassImpl( void ) { [(__bridge id) self breakRetainCycly]; } //打破循環引用,釋放對象 - (void) breakRetainCycly { _retainBlock = nil; }
MyCPPClass.hpp
#ifndef MyCPPClass_hpp #define MyCPPClass_hpp #include <stdio.h> class MyClassImpl; class MyCPPClass { enum { cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42 }; public: MyCPPClass ( void ); ~MyCPPClass( void ); void init( void ); void doSomethingWithMyClass( void ); private: MyClassImpl * _impl; int _myValue; }; #endif /* MyCPPClass_hpp */
MyCPPClass.cpp
#include "MyCPPClass.hpp" #include "MyObject-C-Interface.h" MyCPPClass::MyCPPClass( void ) : _impl ( NULL ) { } void MyCPPClass::init( void ) { _impl = new MyClassImpl(); _impl->init(); } MyCPPClass::~MyCPPClass( void ) { if ( _impl ) { delete _impl; _impl = NULL; } } void MyCPPClass::doSomethingWithMyClass( void ) { int result = _impl->doSomethingWith(&_myValue); if ( result == cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING ) { _impl->logMyMessage("Hello, Arthur!"); } else { _impl->logMyMessage("Don't worry."); } }
main.mm
#include "MyCPPClass.hpp" int main(int argc, const char * argv[]) { @autoreleasepool { MyCPPClass *temp = new MyCPPClass(); temp->init(); temp->doSomethingWithMyClass(); delete temp; } return 0; }
運行結果
第一種經過C語言的方式來調用,使用起來更復雜,因此建議使用C++的方式來實現。須要注意的問題是C++不能管理OC對象的釋放,因此須要利用循環引用。
你能夠在這裏下載demo
參考:https://stackoverflow.com/questions/1061005/calling-objective-c-method-from-c-member-function