Как лучше всего вывести имя класса, чей метод вызывается? - PullRequest
2 голосов
/ 23 января 2012

Мне известно о NSStringFromClass.

Мой вопрос относится к ситуации, когда один и тот же метод реализован в нескольких классах в дереве наследования, и вы хотите отладить информацию о том, из какого класса он выполняется.

Пример:

Пусть у нас есть три класса: A -> B -> C, наследуемые, как показано стрелками.

Если у каждого из них есть методfoo (), определено:

-(void) foo
{
 // Do some work particular to the class it is in.
  .....
  //Each method ends with the debugging statement:
  NSLog("In foo of class:%$",NSClassFromString([self class]));
}

Проблема возникает, когда foo класса B вызывает [super foo].Когда [super foo] (т. Е. Class A) достигает оператора NSLog, [self class] возвращает класс B, а не A.

Аналогично, если C вызвал [super foo], оператор log в super запишет классC.

То, что я хочу сделать, это вывести класс, реализация метода которого выполняется - поэтому, если класс B вызывает [super foo], то оператор log в [A foo] выводит класс A.

Простой способ - заменить NSClassFromString жестко закодированной строкой, представляющей имя класса, но мне было интересно, есть ли лучший способ сделать это?

Ответы [ 4 ]

2 голосов
/ 23 января 2012

Вы можете использовать __PRETTY_FUNCTION__ для включения как класса, так и имени метода:

NSLog(@"Greetings from %s", __PRETTY_FUNCTION__);

Я не верю, что есть макрос времени компиляции только для имени класса.

1 голос
/ 23 января 2012

Проблема возникает, когда foo класса B вызывает [super foo].Когда [super foo] (т.е. класс A) достигает оператора NSLog, [self class] возвращает класс B, а не A.

Конечно.Это потому, что self указывает на объект, и класс этого объекта не меняется только потому, что вы вызываете метод суперкласса.

Простой способ - заменить NSClassFromString жестко закодированной строкой, представляющейимя класса, но мне было интересно, есть ли лучший способ сделать это?

Как уже отмечали другие, вы можете использовать макрос типа __PRETTY_FUNCTION__, но я думаю, что простой и очевидный подходсамый лучшийКогда вы пишете код, вы знаете имя класса, поэтому вы можете написать:

NSLog("In foo of class: %@", @"ClassA");

Каждый из ваших классов имеет собственную реализацию вашего метода, поэтому каждый из них может напечатать свое собственное имя классав сообщении.Нечто подобное __PRETTY_FUNCTION__ полезно, когда вы пишете макрос отладки, который собираетесь использовать в нескольких функциях.Это не тот случай, здесь.Использование очевидного подхода значительно упрощает понимание того, что происходит, и это важно во время отладки (я полагаю, это то, что вы пытаетесь сделать здесь).

1 голос
/ 23 января 2012

Для класса может отсутствовать макрос, но в языке C есть макросы __FILE__ и __LINE__.Они расширяются до текущего файла и номера строки.Вы можете использовать их в NSLog.Я использую __PRETTY_FUNCTION__, когда я помню это, но я помню __FILE__ и __LINE__ больше.

Пример:

NSLog( @"%s %d", __FILE__, __LINE__ );

Помните, что __FILE__ не является цельюСтрока С.

0 голосов
/ 23 января 2012

Я думаю, вам придется пройти вверх по иерархии классов, используя class_getSuperclass и class_getInstanceMethod, сравнивая различия в методах. сделайте это, чтобы определить класс objc, затем используйте class_getName или NSStringFromClass, чтобы получить его имя.

Это будет выглядеть примерно так:

NSString* MONClassNameWhichImplementsMethod(id Self, SEL cmd);

и

- (void)method
{
  NSLog(@"%@ - %@",
    MONGetClassWhichImplementsMethod(self, _cmd),
    NSStringFromSelector(_cmd)
  );
}

и

// NOT COMPILED -- FOR ILLUSTRATION ONLY
Class MONClassWhichImplementsMethod(Class cls, SEL cmd) {
  assert(cls && cmd && "srsly?");

  Class super = class_getSuperclass(cls);
  Method m1 = class_getInstanceMethod(cls, cmd);
  assert(m1 && "srsly?");

  Method m2 = class_getInstanceMethod(super, cmd);
  if (0 == m2) {
    return cls;
  }
  else if (m1 != m2) {
    return cls;
  }
  else {
    return MONClassWhichImplementsMethod(super, cmd);
  }
}

NSString* MONClassNameWhichImplementsMethod(id Self, SEL cmd) {
  return NSStringFromClass(MONClassNameWhichImplementsMethod(Self.class, cmd));
}

если он взорвется от глубокой рекурсии, у вас есть другая проблема.

...