ForwardInvocation 确实存在,但是它很慢并且有令人讨厌的编译器警告问题。所以这让我开始思考 - 有没有一种方法可以使用宏来快速实现一堆从另一个对象获取相关属性的 getter 方法?
例如,如果我有一个 Car 对象,它可能想要实现以下内容:
Car.h:
@class SparkPlug;
@class Engine;
. . .
-(int) nPistons;
-(float) horsepower;
-(SparkPlug*) sparkPlug;
Car.m:
. . .
-(int) nPistons {
return self.engine.nPistons;
}
-(float) horsepower {
return self.engine.horsepower;
}
-(SparkPlug*) sparkPlug {
return self.engine.sparkPlug;
}
问题 -- 是否可以设置一些宏,以便通过在某处进行一个更改,我可以将另一个这样的方法添加到头文件和实现文件中?
例如MagicForwardingMacro (nPistons, int, engine);
理想情况下,如果我以后想使用类似的策略从一个人的 birthCertificate 中获取他或她的名字、姓氏、出生地和出生日期属性,那么这些宏将是可重用的。
最佳答案
最简单的方法可能是动态添加方法:
- 将属性添加到类别中,这样编译器就不会提示太多。
- 在 +[NSObject resolveInstanceMethod:] 中克隆一个合适的 IMP .你需要戳Objective-C runtime .
详细说明第二步:
对于每种类型,添加一个方法,如
-(int)getEngineInt {
return (int()(id,SEL))(objc_msgSend)(engine, _cmd);
}
请注意,对于结构,您需要 objc_msgSend_stret,而对于 float / double ,您可能需要 objc_msgSend_fpret(我认为您只在 i386 上需要它;不确定 AMD64)。支持模拟器和设备的简单破解方法类似于(我忘记了 GCC 使用的宏名称...)
#if __i386
#define objc_msgSend_fpret objc_msgSend
#endif
现在执行+resolveInstanceMethod:
,您需要提前知道您要转到的类(class)。假设它是引擎。
+(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:这可能足以满足您的需求。
编辑:或者,您可以动态循环属性/方法。似乎没有明显的方法来内省(introspection)类别,但您可以在协议(protocol)中定义它们,执行类似 @interface Engine:NSObject<Engine> ... @interface Car(DynamicEngine)<Engine>
的操作。并使用 objc_getProtocol("Engine")
然后protocol_copyMethodDescriptionList()/protocol_copyPropertyList()获取方法,然后添加getter。我不确定是否将属性添加到“方法描述列表”中。另请注意,“复制”函数不会从父类(super class)复制方法/属性,这(在本例中)正是您想要的。
关于iphone - iOS——使用宏转发一堆消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6500729/