Можно ли создать оболочку для каждого вызова метода в Objective-C?

У меня есть проект с большим количеством классов. Я хочу регистрировать (например, в stderr) вызовы каждого селектора во время выполнения.
Мое главное требование — не изменять существующий код, поэтому я не могу просто регистрировать параметры функции в начале каждого вызова.

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

@implementation Class1

// ...

- (int)someFunc:(Class2*) a andClass3:(Class3*)b
{

}

// ...

@end 

Я хочу заменить его чем-то вроде:

- (int)someFuncWrapper:(Class2*) a andClass3:(Class3*)b
{
     NSLog(@"- (int)someFuncWrapper:a andClass3:b <= a=%@, ab=%@", a, b);
     return [someFunc: a andClass3:b];
}

Является ли это возможным?

Я читал об использовании методов, KVO, пересылке сообщений.

Мой текущий подход с использованием методов вызывает бесконечную рекурсию:

- (int)funcToSwizzle:(int)a andB:(int)b
{
    int r = a+b;
    NSLog(@"funcToSwizzle: %d", r);
    return r;
}

- (void)doSimpleSwizzling
{
    NSLog(@"r1 = %d", [self funcToSwizzle:10 andB:20]);

    Class curClass = NSClassFromString(@"HPTracer");

    unsigned int methodCount = 0;
    Method *methods = class_copyMethodList( curClass, &methodCount);

    for (int i=0; i<methodCount; ++i)
    {
        SEL originalSelector = method_getName(methods[i]);
        if ( strcmp("funcToSwizzle:andB:", sel_getName(originalSelector)) == 0 )
        {
            Method m1 = class_getInstanceMethod(curClass, originalSelector);

            id block3 = ^(id self, int a, int b) {
                NSLog(@"My block: %d", a*b);
                // get current implementation of "funcToSwizzle".
                // copy it. store that "IMP"/"void *" etc
                return [self funcToSwizzle:a andB:b];
            };

            IMP imp3 = imp_implementationWithBlock(block3);
            method_setImplementation(m1, imp3);
        }
    }

    NSLog(@"r2 = %d", [self funcToSwizzle:10 andB:20]);
}

И я боюсь, что невозможно сгенерировать block3 или какой-либо метод во время выполнения. Есть NSSelectorFromString, но нет ImplementationFromString.

UPD
Посмотрел утилиту DTrace, вроде очень мощная, но для моих нужд не подходит. Это требует отключения SIP в Mac OS и либо невозможно на iOS, либо возможно на взломанном устройстве.

Что мне нужно от перехвата методов, так это создание стабильной пользовательской «каркаса» как для режимов отладки, так и для режимов производственной сборки.


person Olha    schedule 02.04.2019    source источник
comment
Возможный дубликат Отслеживать все вызовы методов ObjC?   -  person Willeke    schedule 02.04.2019
comment
@Willeke Спасибо, это возможно! Я проверю, может ли этот DTrace получить значения параметров. Если да, то я закрою этот вопрос.   -  person Olha    schedule 02.04.2019
comment
@OlhaPavliuk Есть несколько методов, которые вы могли бы использовать для определения параметров, но в основном все они связаны с ручной сборкой. Дело в том, что из-за того, что objc использует соглашения о вызовах в стиле c, у вас просто нет возможности узнать (на месте вызова) со 100% уверенностью ABI вызова (особенно если вы смешиваете сложные типы или объекты C++ там тоже, что обязательно произойдет в какой-то момент в стеке). Вы можете сделать все возможное, и вы можете даже подумать о горячем обновлении objc_msgSend, но это похоже на тщетную попытку.   -  person Richard J. Ross III    schedule 11.04.2019
comment
Ваш «текущий подход» на самом деле довольно близок к правильному (хотя и без учета правильного соглашения о вызовах функции), вы должны вместо повторного вызова функции (с [self foo:arg1 bar:arg2] получить старый IMP, привести его к правильному типу и вызвать это.   -  person Richard J. Ross III    schedule 11.04.2019
comment
Если вы хотите попробовать решить типы аргументов без использования ассемблера, вы можете посмотреть на swizzling классов и NSInvocation, я давно применил здесь интересный подход, который работал очень хорошо: github.com/parse-community/Parse-SDK -iOS-OSX/blob/master/Parse/ Есть много недостатков в использовании imp_implementationWithBlock, на мой взгляд, на самом деле существует ограничение (примерно 32 КБ) на то, сколько вы можете создать на iOS ( правда по крайней мере до iOS 7).   -  person Richard J. Ross III    schedule 11.04.2019
comment
@RichardJ.RossIII Большое спасибо!!! Я посмотрю на ваше репо, но потребуется несколько часов, чтобы понять ваш подход, поэтому я прокомментирую позже. получите старый IMP, приведите его к нужному типу и вызовите его - спасибо, я попробую.   -  person Olha    schedule 11.04.2019
comment
@ОльхаПавлюк без проблем. Упомяните меня еще раз в этой теме, если вам нужно больше указателей, это может быть довольно сложно понять.   -  person Richard J. Ross III    schedule 12.04.2019