2012-02-10 5 views
3

Я пытаюсь реализовать в 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!).

ответ

2

Есть ли способ, чтобы получить класс объекта, который будет возвращен методом, используя Objective-C среды выполнения от Apple?

Нет - если метод возвращает тип класса, вы не сможете узнать фактический тип бетона до его возвращения. Если неизвестный тип класса неизвестен, вы не можете узнать, какой тип возврата может иметь любой его метод.

+0

Но есть ли функция (или smth else), которая извлекает объявленный тип метода? –

+0

@Vsevolod: В случае, подобном '[[a f] g]', вы можете получить подпись для 'f', но не для' g', не вызывая сначала 'f'. Это потому, что 'f' и' g' - это только имена сообщений и не имеют определенного типа. Вы получаете только сигнатуры методов из классов и селектора комбинаций, протокола и селектора или экземпляра и селектора. –

+0

Должен ли он быть полностью общим или вы можете принять конкретные экземпляры, использовать протоколы со стороны абонента, ...? –

0

Вот как проверить, если "экземпляр" является NSString

if ([instance isKindOfClass:[NSString class]]({ 
    //do something 
} 

Это хорошо?

+0

Нет. Мне нужно получить класс, чтобы не проверять принадлежность объекта к определенному классу. –

+0

хорошо, если у вас есть несколько возможных классов, вы можете проверить, какая из них является вашей переменной, экземпляр, и вы тоже знаете класс. –

0

Вы можете получить фактическое имя класса объекта:

например для объекта foo

NSLog(@"foo is an object of class %@", NSStringFromClass([foo class])); 
+1

Это не мое дело, потому что у меня нет самого объекта.У меня есть метод (фактически не метод, а экземпляр NSInvocation), который возвращает объект. –

+0

В любом случае у вас есть объект - и вы можете использовать его, чтобы узнать, какой класс он есть. Вам не нужно использовать инструкцию NSLog, но функцию 'NSStringFromClass()'. – Abizern