Objective-Cは元のC++ライブラリとどのようにデータ伝達を行うか

6003 ワード

最近、小さなプロジェクトが始まりました.プロジェクトでは、長接続通信用の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 
#include "im_manager.h"
#include 

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を宣言した.さらに1つのプライベートメンバー変数messageReceivedHandlerは、外部に登録されたコールバックを格納し、OnMessageReceivedの方法でデータを送信するために使用される.C++こちらのコードはreadyになっています.次にObjective-Cのドッキングコードを見てみましょう.IMServiceクラスを新規作成し、.m接尾辞を.mmに変更します.ダイレクトコード
IMService.h
#import 
@class MsgModel;

NS_ASSUME_NONNULL_BEGIN

@protocol IMServiceDelegate 
- (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 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)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のアドレスを転送します.ImCallbackImplvoid OnMessageReceived(const ImMessage *message)メソッドは、メッセージを受信すると、コールバックによって中のmessageデータを送信します.ここで、MsgModelクラスを新設し、データをMsgModelオブジェクトに変換した後、 を通じて伝えました.データが必要な場所では、IMServiceオブジェクトを初期化し、そのエージェントメソッドを実装すれば、チャネルから送信されたデータをリアルタイムで受け取ることができます.データを受け取った後、どのように表現したいかはUIの設計の気持ちに従います.
これで、元のC++ライブラリとObjective-Cライブラリとの間のデータ転送とドッキングが完了します.間違いがあれば、指摘交流を歓迎します.
遭遇したピットはIMService.mmvoid gk_messageReceivedHandler(const ImMessage *message)関数の内部でデータを伝達する過程で、頻繁なオブジェクトの作成を減らすために、私は最初に関数の外部に静的MsgModelオブジェクトを作成しました.
static MsgModel *model = [HBMsgModel new];

次に、関数内部でmodelのメンバー変数に値を割り当ててから出力します.チャネルが情報を受け取るのが頻繁ではない場合、これは良いです.その後、チャネル受信メッセージが特に頻繁に発生する場合、送信されたデータが処理に間に合わずに変更され、一部のデータが失われる場合がある.変更してから、穴を埋めることに成功しました!
Enjoy!