最简单的方法可能是动态添加方法:
细化第二步:
对于每种类型,添加一个方法,如
-(int)getEngineInt {
return (int()(id,SEL))(objc_msgSend)(engine, _cmd);
}
请注意,对于结构,您需要 objc_msgSend_stret,对于浮点数/双精度,您可能需要 objc_msgSend_fpret(我认为您只在 i386 上需要它;不确定 AMD64)。支持模拟器和设备的简单技巧类似于(我忘记了 GCC 使用的宏名称......)
#if __i386
#define objc_msgSend_fpret objc_msgSend
#endif
现在要实现+resolveInstanceMethod:
,您需要提前知道要转发到的类。假设它是引擎。
+(BOOL)instancesRespondToSelector:(SEL)name
{
return [Engine instancesRespondToSelector:name];
}
+(BOOL)resolveInstanceMethod:(SEL)name
{
// Do we want to super-call first or last? Who knows...
if ([super resolveInstanceMethod:name]) { return YES; }
// Find the return type, which determines the "template" IMP we call.
const char * returntype = [Engine instanceMethodSignatureForSelector:name].methodReturnType;
if (!returnType) { return NO; }
// Get the selector corresponding to the "template" by comparing return types...
SEL template = NULL;
if (0 == strcmp(returntype,@encode(int))
{
sel = @selector(getEngineInt);
}
else if (0 == strcmp(Returntype,@encode(float))
{
...
}
if (!sel) { return NO; }
Method m = class_getInstanceMethod(self,template);
return class_addMethod(self, name, method_getImplementation(m), method_getTypeEncoding(m));
}
或者,有一个稍微未记录的方法-forwardingTargetForSelector:它可能足够快以满足您的需求。
编辑:或者,您可以动态循环属性/方法。似乎没有一种内省类别的明显方法,但您可以在协议中定义它们,执行类似的操作@interface Engine:NSObject<Engine> ... @interface Car(DynamicEngine)<Engine>
并使用objc_getProtocol("Engine")
,然后使用 protocol_copyMethodDescriptionList()/protocol_copyPropertyList() 来获取方法,然后添加 getter。我不确定是否将属性添加到“方法描述列表”中。另请注意,“复制”功能不会从超类复制方法/属性,这(在这种情况下)是您想要的。