美文网首页
Objective-C 如何与原始 C++ 库进行数据传递

Objective-C 如何与原始 C++ 库进行数据传递

作者: _烩面_ | 来源:发表于2020-01-16 15:18 被阅读0次

最近,开始了一个小项目。项目中需要用到一个 C++ 库用于长连接通信(此库属于自研,而开发者没有Objective-C开发经验)。由于库只提供了接口文件.h.a,需要使用 .h 文件提供的接口协议将数据传递到 Objective-C这边用于展示。这个过程就涉及到了Objective-CC++ 库数据的传递对接。

整体思路:
Objective-C 注册回调到 C++ 的实现文件中去,然后待信道收到数据后通过注册的回调将数据传出来。传出来之后将数据经过Objective-C的对象包装之后再传递出去供使用。

稍微有点抽象,下面我们按照上面的思路一步步看实现。由于仅仅为了演示数据传递的过程,以下均为脱敏过后的精简代码。

首先来看一下C++库提供的.h 都有什么。

// 回调接口
class ImCallback
{
public:
    ImCallback();
    virtual ~ImCallback();

    // 接收消息(一对一、一对多)
    virtual void OnMessageReceived(const ImMessage *message);
};

// 主动调用接口
class IMMANAGER_API ImManager
{
public:
    ImManager();
    virtual ~ImManager();

    // 初始化SDK
    uint32_t Init(ImCallback *callback);
};

ImCallback 是协议类,里面有一个OnMessageReceived 的协议方法是用来接收数据的,需要我们去实现。下面的 ImManager 类则是信道接口类,提供了一个初始化方法uint32_t Init(ImCallback *callback)。参数为遵循 ImCallback 协议的类对象。接下来我们建立一个继承自 ImCallback 的类ImCallbackImpl并实现 OnMessageReceived 方法。如下

#ifndef ImCallbackCpp_hpp
#define ImCallbackCpp_hpp

class ImCallbackImpl : public ImCallback
{
    // 实现接收消息(一对一、一对多)
    void OnMessageReceived(const ImMessage *message)
    {
        // do something
    }
};
#endif 

我们实现了ImCallback中的协议方法void OnMessageReceived(const ImMessage *message)。但在函数内部目前我们什么都没有做。
接下来我们需要实现在函数内部将ImMessage的对象message传出去。如下是ImCallbackImpl实现的完整版。

#ifndef ImCallbackCpp_hpp
#define ImCallbackCpp_hpp

#include <stdio.h>
#include "im_manager.h"
#include <iostream>

typedef void (*OnMessageReceivedHandler) (const ImMessage *message);

class ImCallbackImpl : public ImCallback
{
private:
    OnMessageReceivedHandler messageReceivedHandler;

public:
    virtual void registerOnMessageReceivedHandler(OnMessageReceivedHandler handler) {
        this->messageReceivedHandler = handler;
    }
    
    // 实现接收消息(一对一、一对多)
    void OnMessageReceived(const ImMessage *message)
    {
        this->messageReceivedHandler(message);
    }
};

#endif 

上面我们声明了一个回调函数 OnMessageReceivedHandler 和回调函数注册方法 registerOnMessageReceivedHandler。还一个私有成员变量messageReceivedHandler用于存储外界注册进来的回调,然后在OnMessageReceived方法中将数据传出去。C++这边的代码已经 ready,接下来看一下 Objective-C 方的对接代码。

新建IMService类,并将其.m后缀更改为.mm。直接上代码

IMService.h

#import <Foundation/Foundation.h>
@class MsgModel;

NS_ASSUME_NONNULL_BEGIN

@protocol IMServiceDelegate <NSObject>
- (void)onMessageReceived:(HBMsgModel *)model;
@end

@interface IMService : NSObject

@end

NS_ASSUME_NONNULL_END

IMService.mm

#import "IMService.h"
#import "im_manager.h"
#include "ImCallbackCpp.hpp"
#import "HBMsgModel.h"

@interface IMService ()
@property (nonatomic, weak) id<IMServiceDelegate> delegate;
@end

@implementation IMService {
   ImManager *_imManager;
   ImCallbackImpl *_imCallback;
}

- (instancetype)init {
   self = [super init];
   if (self) {
       _imManager = CreateImManager();
       _imCallback = new ImCallbackImpl;
       _imManager->Init(_imCallback);
       // 注册回调
       _imCallback->registerOnMessageReceivedHandler(hb_messageReceivedHandler);
      
   }
   return self;
}

- (void)startWith:(NSDictionary *)configuration delegate:(id<HBIMServiceDelegate>)delegate {
  // 处理 configuration 
   ...
   // set delegate
   self.delegate = delegate;
}

void gk_messageReceivedHandler(const ImMessage *message) {
   if (self.delegate && [self.delegate respondsToSelector:@selector(onMessageReceived:)]) {
       MsgModel *model = [HBMsgModel new];
       model.from = [NSString stringWithCString:message->from encoding:NSUTF8StringEncoding];
       model.to = [NSString stringWithCString:message->to encoding:NSUTF8StringEncoding];
       model.session_type = message->session_type;
       model.content_type = message->content_type;
       model.content_length = message->content_length;
       model.message_id = [NSString stringWithCString:message->message_id encoding:NSUTF8StringEncoding];
       model.timestamp = message->timestamp;
       model.content = [NSString stringWithCString:message->content encoding:NSUTF8StringEncoding];
       [self.delegate onMessageReceived:model];
   }
}
@end

IMService.mm中我们调用了ImCallbackImpl中的注册函数,将函数gk_messageReceivedHandler的地址传了进去。ImCallbackImpl中的void OnMessageReceived(const ImMessage *message)方法在收到消息后,就会通过回调将里面的 message 数据传出来。这里,我新建了一个MsgModel类,将数据转成MsgModel对象后,通过代理传了出去。哪里需要数据,你只要初始化一个IMService对象并实现其代理方法即可实时的收取到信道发送过来的数据。接到数据后想怎么展现就随UI设计心情了。

至此,就完成了原始C++库与Objective-C之间的数据传递和对接。如有错误,欢迎指正交流。

遇到的坑
IMService.mm中的void gk_messageReceivedHandler(const ImMessage *message)函数内部将数据传递出去的过程中,为了减少频繁的对象创建,我一开始在函数外部创建了一个静态MsgModel对象。

static MsgModel *model = [HBMsgModel new];

然后在函数内部为 model 的成员变量赋值然后再传出去。
信道收取信息不频繁时,这样做挺好的。后来遇到信道接收消息特别频繁的情况,此时传出去的数据可能来不及处理就发生了改变,从而导致部分数据丢失的情况。更改之后,才成功填坑!

Enjoy!

相关文章

网友评论

      本文标题:Objective-C 如何与原始 C++ 库进行数据传递

      本文链接:https://www.haomeiwen.com/subject/xacxzctx.html