OC和C++的相互调用
这篇文章是记录自己学习IOS和C++互相调用的一篇文章,也希望通过自己的自己可以帮助到一些有需要的人,因为也是刚开始学习,可能也有很多不对的地方,希望不要对你造成误解。
- OC调用C++
- 对于OC调用C++,这是比较简单的,因为OC是可以无缝调用C的代码的,在xcode上也是可以直接编译通过的,但是对于C++代码则不行。
- 想调用C++代码需要将.m文件变成.mm文件,此操作对文件而言没有任何影响,只是告诉xcode编译器,此时代码中有C++代码需要将编译器换成C++编译器,即g++,因为gcc无法编译完成C++代码,也只是换个编译器仅此而已,没有别的其他影响。
- 对于OC的import和C++的include都大同小异,不过在OC代码则尽量使用import,因为import可以防止重复包含头文件。
- OC调用C++代码直接在OC文件中进行include即可,那么此时include文件内容都是可以遵循C++规则进行使用即可。
- 因为操作比较简单,这里接不单独写个demo进行使用了,下一个demo将会包含OC调用C++。
- C++调用OC
- C++调用OC相比OC调用C++要复杂一点。
- 因为C++代码无法直接调用OC,所以需要C层进行一层过渡,具体流程是OC层先调用C++层,C++层调用C层,然后C层再去调用OC层,间接完成C++调用OC。
- C层做的事情就是将C++层获取的OC对象的void*指针转化成OC对象,然后通过OC对象进行OC层的调用。
- 因为C层无法获取OC的self对象,所以需要在OC层调用C++时将OC的self强转成void*传递给C++层,并且将C层的函数指针一并传递给C++层,C++层拿到函数指针进行函数调用。
- demo视图如下,也将通过这个demo具体来实现上述所讲,即通过按下start按钮,完成OC层调用C++层,C++层此时开辟一个新线程,后台进行count值的++,每隔1秒,就通过传递过来的C层函数指针,进行函数调用,则C层将void*进行转化成OC对象,然后进行调用OC层页面刷新方法,将此时的count值更新到界面。
ViewController.h
#import <UIKit/UIKit.h>
#include "WorkOnBackground.hpp"
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *textView;
@property (weak, nonatomic) IBOutlet UILabel *textView2;
-(IBAction)startButten;
-(IBAction)stopButten;
-(IBAction)startButten1;
-(IBAction)stopButten2;
-(void)UpdateView:(int)curCount secPtr:(std::string)whichView;
@end
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(IBAction)startButten{
SigletionManager* sig = SigletionManager::getInstance();
sig->handlerEvent("textView", "start", (__bridge void*)self,FunC);
}
-(IBAction)stopButten{
SigletionManager* sig = SigletionManager::getInstance();
sig->handlerEvent("textView", "stop", (__bridge void*)self,FunC);
}
-(IBAction)startButten1{
SigletionManager* sig = SigletionManager::getInstance();
sig->handlerEvent("textView2", "start", (__bridge void*)self,FunC);
}
-(IBAction)stopButten2{
SigletionManager* sig = SigletionManager::getInstance();
sig->handlerEvent("textView2", "stop", (__bridge void*)self,FunC);
}
// OC层页面刷新方法
-(void)UpdateView:(int)curCount secPtr:(std::string)whichView {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// UI更新代码
// NSLog(@"UpdateView :%@",[NSThread currentThread]);
if(whichView == "textView"){
self.textView.text = [NSString stringWithFormat:@"%d",curCount];
}else if(whichView == "textView2"){
self.textView2.text = [NSString stringWithFormat:@"%d",curCount];
}else{
assert(false);
}
}];
}
// C层过渡代码,将void*转化成OC对象,在调用OC层的UpdateView方法进行页面刷新
void FunC(void* obj,int curCount,std::string whichView){
// NSLog(@"FunC :%@",[NSThread currentThread]);
[(__bridge ViewController*)obj UpdateView:curCount secPtr:whichView];
}
@end
WorkOnBackground.hpp(C++层)
#ifndef WorkOnBackground_hpp
#define WorkOnBackground_hpp
#include <thread>
#include <string>
#include <iostream>
#include <unistd.h>
#include <unordered_map>
typedef void(*CallBack)(void* ,int,std::string);
typedef void(*ThreadEntry)(std::string*,CallBack,void*,std::string);
// 线程入口函数,完成调用C层,将void*和count值进行参数传递
void threadEntry(std::string* curState,CallBack callBack,void* obj,std::string whichView){
//TO_DO
int count =0;
while(1){
if((*curState) =="start"){
callBack(obj,count++,whichView);
sleep(1);
}else if((*curState) =="stop"){
return ;
}else{
assert(false) ;
}
}
}
struct ThreadStates{
std::string _curStates;
ThreadStates(std::string curStates,ThreadEntry threadEntry,CallBack callBack,void* obj,std::string whichView):_curStates(curStates){
std::thread curThread(threadEntry,(&_curStates),callBack,obj,whichView);
curThread.detach();
}
};
class SigletionManager{
public:
SigletionManager();
~SigletionManager();
static SigletionManager* _sigletionManager;
static SigletionManager* getInstance();
bool IsExist(std::string whichView);
void handlerEvent(std::string whichView,std::string curStates,void* obj,CallBack callBack);
pthread_mutex_t _lock;
std::unordered_map<std::string, ThreadStates*> _allThreadMap;
};
SigletionManager::SigletionManager(){
pthread_mutex_init(&_lock,NULL);
}
SigletionManager::~SigletionManager(){
pthread_mutex_destroy(&_lock);
}
SigletionManager* SigletionManager::_sigletionManager=NULL;
SigletionManager* SigletionManager::getInstance(){
// 线程不安全
if(_sigletionManager==NULL){
_sigletionManager =new SigletionManager();
}
return _sigletionManager;
}
bool SigletionManager::IsExist(std::string whichView){
if(_allThreadMap.count(whichView)){
return true;
}
return false;
}
// OC层按下按钮调用的C++层代码
void SigletionManager::handlerEvent(std::string whichView,std::string curStates,void* obj,CallBack callBack){
if(IsExist(whichView) && (curStates=="start")){
std::cout<<"This "<<whichView<<" is started"<<std::endl;
}else if(IsExist(whichView) && (curStates=="stop")){
std::cout<<"This "<<whichView<<" will stop"<<std::endl;
_allThreadMap[whichView]->_curStates=curStates;
_allThreadMap.erase(whichView);
}else if((!IsExist(whichView)) &&(curStates=="stop")){
std::cout<<"The View no exist"<<std::endl;
}else{
_allThreadMap[whichView] = new ThreadStates(curStates,threadEntry,callBack,obj,whichView);
}
}
#endif /* WorkOnBackground_hpp */
这就是demo的设计,但是其中单例是没有必要的,可以每个按钮对应一个线程,对于unordered_map则是为了将线程进行一个有效的识别,对于多队按钮都可以有效的控制。此篇也是自己学习记录,帮助日后自己可以进行回顾,也希望可以帮助到刚学习的你。