Ric*_*III 25 c++ cocoa objective-c objective-c++ ios
所以,今天我很无聊,并决定搞乱C++/Obj-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();
};
Run Code Online (Sandbox Code Playgroud)
如您所见,界面非常简单易懂.我们创建两个(几乎)相同的接口,一个用于C++对象,另一个用于Obj-C协议.
现在,我找到了一种方法来实现这一点,但是让自己好斗,这变得丑陋:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
我将总结一下它的作用:
现在,正如您所看到的,这不是很灵活,但确实有效,而且它是双向的:
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;
Run Code Online (Sandbox Code Playgroud)
您也可以使用创建对象new NSCPPObj(15),但记得删除它!显然,这可以在ARC或非ARC环境中工作,但ARC需要一些额外的桥接转换.
所以,我提出了一个真正的问题:
这种设计结构的优点/缺点是什么?我可以列出一些我的头脑:
优点:
缺点:
那么,毕竟,你会在应用程序中推荐这种设计结构吗?为什么
bbu*_*bum 23
那么,毕竟,你会在应用程序中推荐这种设计结构吗?为什么
没有.
这是一个非常好的代码; 我特别喜欢使用imp_implementationWithBlock()(但我承认我可能偏向于运行时的特定功能;).当然,像这样的探索总是一种非常有价值的学习工具.
在"真实付费项目"使用的上下文中,问题在于您正在有效地创建一个相对通用的桥接器,然后必须在任一端具有特定的桥接器以与典型的C++库或典型的Objective-C API接口/库.换句话说,您已经有效地创建了一个新的运行时,该运行时源自两个现有运行时的合并.
而且,正如你在Cons中所指出的那样,你几乎必须触摸,包装,修改和/或调试一个垫片,在你想要带入这个模式的每个C++类之上.
在过去20多年中使用相当多的Objective-C++代码时,这样的桥通常比它的价值更麻烦.您可能会更好 - 花更少的时间编写和调试代码 - 围绕C++(或C,坦率地)API创建简单的Objective-C包装,然后可以与目标系统的Objective-C框架集成并使用它们.