Я пытаюсь реализовать в Objective-C прокси для объекта следующим образом:Получение класс возвращаемого объекта в 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: and forwardInvocation :. Второй довольно простой, но во-первых, это вопрос.
Мы должны знать класс проксифицированного объекта, чтобы иметь возможность предоставлять подпись, но вызов, который инициализируется другойProxy, не предоставляет информацию о классе возвращаемого объекта. Есть ли способ получить класс объекта, который будет возвращен методом с использованием среды выполнения Objective-C от Apple?
UPDATE:
Я понимаю, что фактический класс возвращаемого объекта может быть различным, но может быть единственным классом, с которым метод объявлен. Если метод объявлен как
- (SomeClass*) someMethod;
В интерфейсе я ожидаю, что SomeClass будет получен.
UPDATE:
Наконец я решил мою проблему. Решение не изящно, но оно просто работает. Я написал этот метод:
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!).
Но есть ли функция (или smth else), которая извлекает объявленный тип метода? –
@Vsevolod: В случае, подобном '[[a f] g]', вы можете получить подпись для 'f', но не для' g', не вызывая сначала 'f'. Это потому, что 'f' и' g' - это только имена сообщений и не имеют определенного типа. Вы получаете только сигнатуры методов из классов и селектора комбинаций, протокола и селектора или экземпляра и селектора. –
Должен ли он быть полностью общим или вы можете принять конкретные экземпляры, использовать протоколы со стороны абонента, ...? –