Возможно, проще всего динамически добавить методы:
Разработка второго шага:
Для каждого типа добавьте метод, такой как
-(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 () для получить методы, а затем добавить получатели. Я не уверен, добавлены ли свойства в «список описания метода». Также обратите внимание, что функции «copy» не копируют методы / свойства из суперклассов, что (в данном случае) - то, что вам нужно.