6

iOSプロジェクトでプロトコルバッファを使用したい。プロジェクト全体をObjective-C++の大失敗にしないようにしているので、C++のprotobufクラスをObjective-Cのクラスにラップしたいと思います。私は数十のprotobufメッセージを持っており、一度に1つのクラスでこれを正常に実行しましたが、理想的には、継承を使用して繰り返されるコードを最小限に抑えたいと思います。私はObjective-Cを初めて使用し、10年間C ++についてほとんど知らなかったものを使用していなかったため、これは主にフラストレーションの練習でした。以下は、私が1つのメッセージをどのようにラップしたかの例です。

コード

.proto:

message MessageA {
    optional string value = 1;
}

MessageAWrapper.h:

#import <Foundation/Foundation.h>

@interface MessageAWrapper : NSObject

@property (nonatomic) NSString *value;

+ (id)fromString:(NSString *)string;
- (NSString *)serialize;

@end

MessageAWrapper.mm:

#import "MessageA.h"
#import "message.pb.h"

@interface MessageAWrapper ()

@property (nonatomic) MessageA *message;

@end

@implementation MessageAWrapper

- (id)init
{
    self = [super init];
    if (self) {
        self.message = new MessageA();
    }
    return self;
}

- (void)dealloc {
    delete self.message;
    self.message = NULL;
}

- (NSString *)value {
    return [NSString stringWithUTF8String:self.message->value().c_str()];
}

- (void)setValue:(NSString *)value {
   self.message->set_value([value UTF8String]);
}

- (NSString *)serialize {
    std::string output;
    self.message->SerializeToString(&output);
    return [NSString stringWithUTF8String:output.c_str()];
}

+ (id)fromString:(NSString *)string {
    MessageA *message = new MessageA();
    message->ParseFromString([string UTF8String]);

    MessageAWrapper *wrapper = [[MessageAWrapper alloc] init];
    wrapper.message = message;
    return wrapper;
}

@end

ゴール

ここには何十回も繰​​り返されるコードがたくさんあり、そのバリエーションはラップされたクラスタイプ(、、、、)だけinitなのでdealloc、理想的serializeには代わりに親クラスにfromString配置したいと思います。ProtobufMesssage残念ながら、親クラスが子が使用しているクラスを知る方法が見つからないため、この作業を行うことに成功しませんでした。これは、たとえば、で必要initですfromString

私が試したこと

  • 構造体
  • テンプレートクラス
  • 空所*

私が遭遇した障害

  • クラス/タイプへの参照を格納する方法が見つかりません
  • .hファイルにC++ヘッダーまたはコードを含めることはできません(これには、プロジェクト全体がObjective-C ++である必要があるため)
  • 抽象的であるため、protobufメッセージの親(Messageまたは)への参照を維持するのが難しいMessageLite

私が言ったように、私はC++またはObjective-Cについてほとんど理解していません。私の経験のほとんどは、PythonやJavaなどの高級言語での経験です(ただし、ポインターなどの基本的なCのことはほとんど理解しています)。

これはおそらく不可能ですか?私はそれに間違ってアプローチしていますか、それとも明らかな何かを見逃していますか?どんな助けでも大歓迎です。ありがとう。

4

2 に答える 2

0

私は C++ についてはまったく詳しくありませんが、Objective-C のプロパティを であると宣言することはできませんMessage *か?

.mm ファイルでプロパティを宣言することにより、ヘッダーから C++ コードを既に分離しています。問題は、コンパイラによって名前が付けられたインスタンス メソッド (value()およびset_value()) であり、サブクラスに対してのみ有効なメソッドです。Reflectionクラスを使用して、名前でフィールドを取得および設定すると役立つ場合があります。これを示すGoogleの抜粋を次にmessage.h示します。

Message* foo = new Foo;
const Descriptor* descriptor = foo->GetDescriptor();

const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
assert(text_field != NULL);
assert(text_field->type() == FieldDescriptor::TYPE_STRING);
assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);

const Reflection* reflection = foo->GetReflection();
assert(reflection->GetString(foo, text_field) == "Hello World!");

タイプチェックを行い、値を取得または設定する Objective-C-objectForKey:および-setObject:forKey:インスタンス メソッドを作成できます (紛らわしいことに、 の場合のキーは にMessageAWrapperなります@"value")。サブクラスは C++ コードを認識する必要さえありません。

のクリエーター関数-init+fromString:メソッドを次のように分離することもでき+_createNewInstanceます。

+(Message*)_createNewInstance{ return new MessageA(); }

のサブクラスがMessageWrapper、C++ オブジェクトの作成を除くすべてのコードを再利用できるようにします。

于 2013-02-21T05:46:03.530 に答える
0

Objective C には非常に強力なインストロスペクション機能がありますが、C++ にはより制限があります。RTTI (ランタイム型情報) はありますが、Objective C ほど強力ではありません。

ただし、それで十分かもしれません。Objective C++ クラス内では、typeid 演算子を使用してメッセージ オブジェクトの型を見つけることができます。

if( (typeid(self.message) == typed(foo)){
  //doSomething
else if( (typeid(self.message) == typed(bar)){
  // doSomething else
}

おそらく最良のオプションは、別の間接化レベルを追加することです。すべてのプロトコル バッファ C++ クラスをラップする Objective C クラス階層を作成し、それらのクラスを使用する別の Objective C を作成します (おそらくデリゲートとして)。これはより良い選択肢かもしれないと思います。C++ は、避けられない場合にのみ使用してください。

幸運を!

于 2013-08-26T20:51:50.090 に答える