2009-11-25 3 views
10

Пример: Когда вызывается мой метод -fooBar, я хочу, чтобы он запустил консоль, другой метод которой вызвал другой класс.Как узнать, кто вызвал метод?

Прямо сейчас, я только знаю, как войти имя метода самого и своего класса Foobar, с этим:

_cmd 

[self class] 

Возможно ли это выяснить?

ответ

36

В полностью оптимизированном коде нет 100% -ного уверенного способа определить вызывающего абонента по определенному методу. Компилятор может использовать оптимизацию хвостового вызова, тогда как компилятор эффективно повторно использует стек стека вызывающего абонента для вызываемого абонента.

Чтобы увидеть пример этого, установите точку останова для любого метода, используя gdb, и посмотрите на обратную трассировку. Обратите внимание, что вы не видите objc_msgSend() перед каждым вызовом метода. Это связано с тем, что objc_msgSend() выполняет хвостовой вызов для реализации каждого метода.

Несмотря на то, что вы можете скомпилировать приложение не оптимизированным, вам понадобится не оптимизированная версия всех системных библиотек, чтобы избежать этой проблемы.

И это только одна проблема; по сути, вы спрашиваете: «Как я могу изобрести CrashTracer или gdb?». Очень сложная проблема, на которой сделаны карьеры. Если вы не хотите, чтобы «инструменты отладки» были вашей карьерой, я бы рекомендовал не идти по этой дороге.

На какой вопрос вы действительно пытаетесь ответить?

+3

Это анти-ответ. –

+7

@alexgray Как это анти-ответ?Ответ точно точен по масштабу и масштабу проблемы, и, учитывая принятый и окончательный вопрос, мы надеемся, что ОП пойдет по пути к успеху. – bbum

3

Это не возможно в общем случае без фактической ходьбы от стека. Там даже нет гарантии, что другой объект отправит сообщение, вызвавшее этот метод. Например, он может быть вызван из блока в обработчике сигналов.

1

Эта информация может быть получена с использованием DTrace.

1

Сделать макрос, который добавляет __FUNCTION__ к имени функции для вызова функции. Затем этот макрос вызовет вашу функцию с дополнительным параметром char * целевой функции.

+0

Это предполагает, что у вас есть контроль над вызывающим абонентом и можете изменить ABI между вызывающим и калом lee, изменяя аргументацию, что редко бывает. – bbum

6

Как насчет this:

NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1]; 

NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -[]+?.,"]; 
NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString componentsSeparatedByCharactersInSet:separatorSet]]; 
[array removeObject:@""]; 

NSLog(@"Class caller = %@", [array objectAtIndex:3]); 
NSLog(@"Method caller = %@", [array objectAtIndex:4]); 

Кредиты автора оригинала, intropedro.

+3

Это не будет работать в полностью оптимизированном коде, поскольку оптимизация хвостового вызова делает кадры полностью исчезными из стека. – bbum

2

Пользователь метод ниже
индекс Pass, для которого вы хотите отобразить метод и передать -1, если вы хотите, чтобы отобразить полный стек метода

+(void) methodAtIndex:(int)index{ 
    void* callstack[128]; 
    int frames = backtrace(callstack, 128); 
    char** strs = backtrace_symbols(callstack, frames); 

    if (index == -1) { 
     for (int i = 0; i < frames; ++i) { 
      printf("%s\n", strs[i]); 
     } 
    } 
    else { 
     if (index < frames) { 
      printf("%s\n", strs[index]); 
     } 
    } 
    free(strs); 

} 
+0

Я получаю 'error: warning: не удалось получить указатель cmd (заменяя NULL): в этом фрейме нет переменной с именем '_cmd' – ReDetection

0

я пытался поймать, кто, как и когда размер окна Изменения и сделал некоторую ручную работу:

- (void)logWindowWidth:(NSString *)whoCalls { 
    NSLog(@"%@", whoCalls); 
    NSLog(@"self.window.size.width %f", self.window.size.width); 
} 

-(void)someMethod { 
    [self logWindowWidth:@"someMethod - before"]; 
    ... 
    [self logWindowWidth:@"someMethod - after"]; 
} 

-(void)anotherMethod { 
    [self logWindowWidth:@"anotherMethod - before"]; 
    ... 
    [self logWindowWidth:@"anotherMethod - after"]; 
} 
1
NSLog(@"Show stack trace: %@", [NSThread callStackSymbols]); 
Смежные вопросы