2012-04-04 6 views
25

私は今日退屈で、C++/Obj-C補間法を使いこなすことに決めました。とても面白いセットアップを作成する方法を見つけました。Objective-C - C++によるブリッジングの短所?

@protocol NSCPPObj <NSObject> 

-(id) init; 
-(id) initWithInt:(int) value; 
-(int) somethingThatReturnsAValue; 
-(void) doSomething; 

@end 

class NSCPPObj : objc_object { 
public:  
    static Class cls(); 

    int iVar; 

    NSCPPObj(); 
    NSCPPObj(int); 

    int somethingThatReturnsAValue(); 
    void doSomething(); 
}; 

ご覧のとおり、インターフェイスはかなりわかりやすく分かりやすいです。 C++オブジェクト用とObj-Cプロトコル用の2つ(ほぼ同じ)のインタフェースを作成します。

は今、私はこれを実装する方法を見つけましたが、自分自身を引き締める、これは醜い取得します。

// NSCPPObj.mm 
#import <objc/runtime.h> 
#import <iostream> 

#import "NSCPPObject.h" 

Class NSCPPObj_class = nil; 

__attribute__((constructor)) 
static void initialize() 
{ 
    NSCPPObj_class = objc_allocateClassPair([NSObject class], "NSCPPObj", 0); 

    class_addMethod(NSCPPObj_class->isa, @selector(alloc), imp_implementationWithBlock(^(id self) { 
     return class_createInstance(NSCPPObj_class, sizeof(struct NSCPPObj)); 
    }), "@@:"); 

    class_addMethod(NSCPPObj_class, @selector(init), imp_implementationWithBlock(^(id self) { 
     return self;   
    }), "@@:"); 

    class_addMethod(NSCPPObj_class, @selector(initWithInt:), imp_implementationWithBlock(^(id self, int value) { 
     ((struct NSCPPObj *) self)->iVar = value; 

     return self; 
    }), "@@:i"); 

    class_addMethod(NSCPPObj_class, @selector(doSomething), imp_implementationWithBlock(^(id self) { 
     ((struct NSCPPObj *) self)->doSomething(); 
    }), "[email protected]:"); 
    class_addMethod(NSCPPObj_class, @selector(somethingThatReturnsAValue), imp_implementationWithBlock(^(id self) { 
     return ((struct NSCPPObj *) self)->somethingThatReturnsAValue(); 
    }), "[email protected]:"); 

    objc_registerClassPair(NSCPPObj_class); 
} 

Class NSCPPObj::cls() 
{ 
    return NSCPPObj_class; 
} 

NSCPPObj::NSCPPObj() 
{ 
    this->isa = NSCPPObj_class; 
    [((id<NSCPPObj>) this) init]; 
} 

NSCPPObj::NSCPPObj(int value) 
{ 
    this->isa = NSCPPObj_class; 
    [((id<NSCPPObj>) this) initWithInt:value]; 
} 

void NSCPPObj::doSomething() 
{ 
    std::cout << "Value Is: " << [((id<NSCPPObj>) this) somethingThatReturnsAValue] << std::endl; 
} 

int NSCPPObj::somethingThatReturnsAValue() 
{ 
    return iVar; 
} 

私はこれが何をするか要約します:

  1. は、クラスペア
  2. を割り当てすべてのクラスメソッドとインスタンスメソッドをオブジェクトに追加します
  3. クラスペアを登録します

あなたが見ることができるように今、これは非常に柔軟ではないが、それは仕事をし、そしてそれは、双方向の通りです:

id<NSCPPObj> obj = [[NSCPPObj::cls() alloc] initWithInt:15]; 
[obj doSomething]; 

NSLog(@"%i", [obj somethingThatReturnsAValue]); 
NSLog(@"%@", obj); 

NSCPPObj *objAsCPP = (__bridge NSCPPObj *) obj; 

objAsCPP->doSomething(); 
std::cout << objAsCPP->somethingThatReturnsAValue() << std::endl; 

あなたはまたnew NSCPPObj(15)を使用して、オブジェクトを作成し、それに覚えることができます消して! 明らかに、これはARC環境または非ARC環境では機能しますが、ARCではいくつかの余分なブリッジキャストが必要です。

私は本当の質問になります:
このデザイン構造の長所と短所は何ですか?私は私の頭の上のオフ数を一覧表示することができます。

長所:

  1. にObjC
  2. との結合C++
  3. 動的メソッドのオーバーロード演算子は、C++またはにObjCのファッションのいずれかで構築することができます

短所:

  1. 読みにくい実装
  2. セレクタ&バインディングは、すべてのC++実装のために追加する必要があります
  3. Classオブジェクトが直接

ので参照することはできませんインターフェースに追加、すべてのことの後、あなたがこれをお勧めしますアプリケーションの設計構造と理由。

+1

私はこの良い行く応答を与えるために、あまりにも少しのC++を知っているが、これに対する答えは、あなたが取り組んでいるアプリケーションのまさに種類に依存しているのだろうか。既存のC++ゲームを移植すると、これは単純なユーティリティアプリよりもはるかに役立ちます。シーズニングされたC++プログラマーは、Objective-C指向の人よりも高く評価します。 – lxt

+1

再投票する投票。私はこれがいかに建設的ではないかもしれないのか理解していますが、これはコミュニティサイトです。私はあなたが司会者であることを認識していますが、あなたがこれを閉じることを望んでいる唯一の人であることを見ています。 –

+0

私は司会者ではなく、私はこの質問に審査のためにフラグを立てました。それは話題にならない。 – mydogisbox

答えて

23

だから、すべてのことの後、あなたは アプリケーションでこの設計構造を勧めますか?なぜ。

本当にいいコードです。私は特にimp_implementationWithBlock()の使用が好きです(ただし、私はランタイムのその特定の機能に部分的かもしれません;)。そして、もちろん、このような探索は、常に非常に貴重な学習ツールです。

"現実世界の有料プロジェクト"という文脈では、一般的なC++ライブラリや一般的なObjectiveのいずれかとインターフェースするために、両端に特定のブリッジを持たなければならない比較的一般的なブリッジを効果的に作成している-C API /ライブラリ。別の言い方をすれば、既存のランタイムを2つ組み合わせた新しいランタイムを効果的に作成することができます。

そして、あなたが短所で指摘するように、あなたはかなり、ラップに触れ、変更および/またはあなたがこのパターンに持って帰りたいと思うすべてのC++クラスの上にシムをデバッグする必要があります。

最後の20年以上にわたるのObjective-C++コードのかなりの作業では、このようなブリッジは、一般的に、それは価値があるよりも多くのトラブルです。ターゲットコードのObjective-Cフレームワークと統合して使用することができるC++(またはC、真っ直ぐな)APIの周りに単純なObjective-Cラッパーを作成する方が、コードの作成とデバッグにかかる​​時間が短くて済みます。