Как узнать, кто вызвал метод?

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

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

_cmd

[self class]

Можно ли это выяснить?

Ответ 1

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

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

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

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

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

Ответ 2

Как насчет этого:

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

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

Ответ 5

Пользователь использует метод ниже
Пропустить индекс, для которого вы хотите отобразить метод, и передать -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);

}

Ответ 6

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

Ответ 7

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

Ответ 8

NSLog(@"Show stack trace: %@", [NSThread callStackSymbols]);

Ответ 9

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

- (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"];
}