У меня есть проект с большим количеством классов. Я хочу регистрировать (например, в 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, либо возможно на взломанном устройстве.
Что мне нужно от перехвата методов, так это создание стабильной пользовательской «каркаса» как для режимов отладки, так и для режимов производственной сборки.
[self foo:arg1 bar:arg2]
получить старыйIMP
, привести его к правильному типу и вызвать это. - person Richard J. Ross III   schedule 11.04.2019