IOS_C++和OC的互相调用

本文详细介绍了Objective-C (OC) 和 C++ 相互调用的方法与实践,包括OC如何调用C++代码及C++如何通过C层调用OC。演示了一个通过按钮控制后台计数并实时更新UI的示例,涉及线程、回调函数和单例管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

OC和C++的相互调用

这篇文章是记录自己学习IOS和C++互相调用的一篇文章,也希望通过自己的自己可以帮助到一些有需要的人,因为也是刚开始学习,可能也有很多不对的地方,希望不要对你造成误解。

  • OC调用C++
  1. 对于OC调用C++,这是比较简单的,因为OC是可以无缝调用C的代码的,在xcode上也是可以直接编译通过的,但是对于C++代码则不行。
  2. 想调用C++代码需要将.m文件变成.mm文件,此操作对文件而言没有任何影响,只是告诉xcode编译器,此时代码中有C++代码需要将编译器换成C++编译器,即g++,因为gcc无法编译完成C++代码,也只是换个编译器仅此而已,没有别的其他影响。
  3. 对于OC的import和C++的include都大同小异,不过在OC代码则尽量使用import,因为import可以防止重复包含头文件。
  4. OC调用C++代码直接在OC文件中进行include即可,那么此时include文件内容都是可以遵循C++规则进行使用即可。
  5. 因为操作比较简单,这里接不单独写个demo进行使用了,下一个demo将会包含OC调用C++。
  • C++调用OC
  1. C++调用OC相比OC调用C++要复杂一点。
  2. 因为C++代码无法直接调用OC,所以需要C层进行一层过渡,具体流程是OC层先调用C++层,C++层调用C层,然后C层再去调用OC层,间接完成C++调用OC。
  3. C层做的事情就是将C++层获取的OC对象的void*指针转化成OC对象,然后通过OC对象进行OC层的调用。
  4. 因为C层无法获取OC的self对象,所以需要在OC层调用C++时将OC的self强转成void*传递给C++层,并且将C层的函数指针一并传递给C++层,C++层拿到函数指针进行函数调用。
  5. 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

ViewController.mm

#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则是为了将线程进行一个有效的识别,对于多队按钮都可以有效的控制。此篇也是自己学习记录,帮助日后自己可以进行回顾,也希望可以帮助到刚学习的你。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值