有没有办法记录对给定类的每个方法的每次调用?

Que*_*tin 3 debugging objective-c uiview ios

我正在寻找一种方法来记录对给定 UIView 的每个方法的每次调用以进行调试。

Bry*_*hen 5

这是我写的代码

使用以下步骤:

  1. 通过从子类化创建代理类 NSProxy
  2. SwizzleallocWithZone:在目标类上并用代理类包装返回的对象
  3. forwardInvocation:在代理类中登录消息

#import <objc/runtime.h>

@interface XLCProxy : NSProxy

+ (id)proxyWithObject:(id)obj;

@end

@implementation XLCProxy
{
    id _obj;
}

+ (void)load
{
    {
        Class cls = NSClassFromString(@"IDESourceCodeDocument");
        id metacls = object_getClass(cls);
        IMP imp = class_getMethodImplementation(metacls, @selector(allocWithZone:));
        IMP newimp = imp_implementationWithBlock(^id(id me, SEL cmd, NSZone *zone) {
            id obj = ((id (*)(id,SEL,NSZone*))(imp))(me, cmd, zone);
            return [XLCProxy proxyWithObject:obj];
        });
        BOOL success = class_addMethod(metacls, @selector(allocWithZone:), newimp, [[NSString stringWithFormat:@"@@:%s", @encode(NSZone*)] UTF8String]);
        if (!success) {
            NSLog(@"Add method failed");
        }
    }
}

+ (id)proxyWithObject:(id)obj
{
    XLCProxy *proxy = [self alloc];
    proxy->_obj = obj;
    return proxy;
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    const char *selname = sel_getName([invocation selector]);

    [invocation setTarget:_obj];
    [invocation invoke];

    if ([@(selname) hasPrefix:@"init"] && [[invocation methodSignature] methodReturnType][0] == '@') {
        const void * ret;
        [invocation getReturnValue:&ret];
        ret = CFBridgingRetain([XLCProxy proxyWithObject:_obj]);
        [invocation setReturnValue:&ret];
    }


    NSLog(@"%@ %s", [_obj class], selname);
//    if ([[invocation methodSignature] methodReturnType][0] == '@') {
//        NSObject __unsafe_unretained * obj;
//        [invocation getReturnValue:&obj];
//        NSLog(@"%@", obj);
//    }
}

-(NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    return [_obj methodSignatureForSelector:sel];
}

- (Class)class
{
    return [_obj class];
}

@end
Run Code Online (Sandbox Code Playgroud)