Objective-C – 与C ++桥接的缺点?

所以,我今天很无聊,决定搞乱C ++ / Obj-C插值,并且find了创build一个非常有趣的设置的方法。

@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(); }; 

正如你所看到的,界面非常简单易懂。 我们创build两个(几乎)相同的接口,一个用于C ++对象,另一个用于Obj-C协议。

现在,我find了一个方法来实现这一点,但是振作起来,这会变得很难看:

 // 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(); }), "v@:"); class_addMethod(NSCPPObj_class, @selector(somethingThatReturnsAValue), imp_implementationWithBlock(^(id self) { return ((struct NSCPPObj *) self)->somethingThatReturnsAValue(); }), "i@:"); 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)来创build对象,但请记得删除它! 显然,这可以在ARC或非ARC环境中工作,但ARC需要一些额外的桥接转换。

所以,我来真正的问题:
这种devise结构的优点/缺点是什么? 我可以列举几个我的头顶:

优点:

  1. 运算符用C ++重载
  2. dynamic方法绑定与ObjC
  3. 可以用C ++或ObjC方式构build

缺点:

  1. 难以阅读的实施
  2. 必须为添加到接口的每个C ++实现添加select器和绑定
  3. Class对象不能被直接引用

所以,毕竟, 你会在一个应用程序中推荐这个devise结构吗? 为什么。

所以,毕竟,你会在一个应用程序中推荐这个devise结构吗? 为什么。

没有。

这是一个非常好的代码; 我特别喜欢imp_implementationWithBlock()的使用(但我承认我可能偏爱运行时的特定function)。 当然,这样的探索永远是一个非常有价值的学习工具。

在“真实世界支付项目”中使用的问题是,您正在有效地创build一个相对通用的桥接器,然后必须在两端都有特定的桥接器来与典型的C ++库或典型的Objective-C API /库。 换句话说,您已经有效地创build了一个从两个现有运行时合并而来的新运行时。

而且,正如你在Cons中指出的那样,你几乎必须在你想要进入这个模式的每一个C ++类的基础上接触,包装,修改和/或debugging垫片。

在过去的20多年里,在处理相当多的Objective-C ++代码时,像这样的桥通常比它的价值更麻烦。 你可能会更好 – 花更less的时间编写和debugging代码 – 围绕C ++(或C,坦率地说)API创build简单的Objective-C包装,然后可以将其与目标系统的Objective-C框架集成并使用。