代码之家  ›  专栏  ›  技术社区  ›  olha

是否可以为Objective-C中的每个方法调用生成一个包装器?

  •  0
  • olha  · 技术社区  · 5 年前

    我想在运行时记录(例如,到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];
    }
    

    有可能吗?

    我读过一些关于swizzing、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公司
    它需要在Mac操作系统上禁用SIP,在iOS上是不可能的,或者在越狱设备上是可能的。

    从方法拦截中我需要的是为调试和生产构建模式创建一个稳定的自定义“框架”。

    0 回复  |  直到 5 年前