Я пытаюсь реализовать в Objective-C прокси для объекта следующим образом:
- (NSMethodSignature*) methodSignatureForSelector:(SEL)sel
{
return [_proxifiedObject methodSignatureForSelector:sel];
}
- (void) forwardInvocation:(NSInvocation *)invocation
{
char returnType = invocation.methodSignature.methodReturnType[0];
if(returnType == '@')
{
id anotherProxy = [[[MyProxy alloc] initWithInvocation:invocation] autorelease];
[invocation setReturnValue:&anotherProxy];
} else {
invocation.target = _proxifiedObject;
[invocation invoke];
}
}
Другой прокси должен создать объект из этого вызова.Но пока объект находится в стадии разработки, мы должны иметь возможность собирать и хранить вызовы к нему, чтобы иметь возможность обработать их после того, как объект будет построен.Для достижения этого я должен реализовать 2 метода: methodSignatureForSelector: и forwardInvocation :.Второе довольно просто, но первое, о чем весь вопрос.
Мы должны знать класс проксифицированного объекта, чтобы иметь возможность предоставить подпись, но вызов, с которым инициализируется другойProxy, не предоставляет информацию о классе возвращаемого объекта.Есть ли способ получить класс объекта, который будет возвращен методом с использованием среды выполнения Apple Objective-C?
ОБНОВЛЕНИЕ :
Я понимаю, что фактическоекласс возвращаемого объекта может отличаться, но может быть единственный класс, с которым объявлен метод.Если метод объявлен как
- (SomeClass*) someMethod;
в интерфейсе, я ожидаю получить SomeClass.
ОБНОВЛЕНИЕ :
Наконец я решил своюпроблема.Решение не элегантное, но оно «просто работает».Я написал этот метод:
static NSMutableDictionary* dictionarySelectorsToSignatures;
+ (NSMethodSignature*) methodSignatureForUnknownClassForSelector: (SEL) sel
{
NSMethodSignature* candidate = [dictionarySelectorsToSignatures objectForKey:[NSNumber numberWithLongLong:(long long) sel]];
if(candidate == nil)
{
int classesCount = objc_getClassList(NULL, 0);
Class* classes = malloc(sizeof(Class) * classesCount);
objc_getClassList(classes, classesCount);
for(int i = 0; i < classesCount; i++)
{
if(class_getClassMethod(classes[i], @selector(instanceMethodSignatureForSelector:)) != NULL)
{
NSMethodSignature* signature = [classes[i] instanceMethodSignatureForSelector:sel];
if(signature != nil)
{
if(candidate != nil)
{
if(![candidate isEqual:signature])
{
return nil;
}
} else {
candidate = signature;
}
}
}
}
if(candidate != nil)
{
[dictionarySelectorsToSignatures setObject:candidate
forKey:[NSNumber numberWithLongLong:(long long) sel]];
}
}
return candidate;
}
Этот метод возвращает подпись для селектора, если он не является неоднозначным и ноль в другом случае.Его основным недостатком является тот факт, что он не поддерживает модификацию классов / списков классов во время выполнения, поэтому его можно использовать только в том случае, если все классы зарегистрированы и код не изменяет классы (потенциально рискованно использовать его с KVO!).