捕获对象上的所有方法/消息调用

Jac*_*cob 6 cocoa objective-c nsobject

如何在对象上放置一个"钩子",以便我可以看到正在向它发送的消息?(即每次向对象发送消息时执行NSLog()).

我想回想一下之前就已经完成了这件事,但我忘记了.我在想它可能有助于我找出部分代码无效的原因.

mfa*_*kas 18

您还可以使用objective-c转发.基本上,您可以创建一个记录方法的代理对象,然后将调用转发给原始方法.有关详细信息,请参阅我的博文.

@interface LoggerProxy : NSObject
{
    id original;
}

- (id)initWithOriginal:(id) value;

@end
@implementation LoggerProxy

- (id) initWithOriginal:(id)value
{
    if (self = [super init]) {
        original = value;
    }
    return self;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    NSMethodSignature *sig = [super methodSignatureForSelector:sel];
    if(!sig)
    {
        sig = [original methodSignatureForSelector:sel];
    }
    return sig;
}

- (void)forwardInvocation:(NSInvocation *)inv
{
    NSLog(@"[%@ %@] %@ %@", original, inv,[inv methodSignature],
         NSStringFromSelector([inv selector]));
    [inv invokeWithTarget:original];
}

@end
Run Code Online (Sandbox Code Playgroud)

  • 我只是尝试了这个,它在某种程度上起作用.我正在尝试使用MKPinAnnotationView,当它尝试调用[MKPinAnnotationView superlayer]时,它会因NSInvalidArgumentException而崩溃.所以它试图将它发送到没有这种方法的对象? (2认同)

Lou*_*arg 8

执行此操作的最佳方法是使用dtrace或乐器脚本.使用dtrace,您可以执行以下操作:

将以下脚本写为objc-calls.d

#pragma D option quiet
objc$target:::entry
{
   printf("%s %s\n", probemod, probefunc);
}
Run Code Online (Sandbox Code Playgroud)

然后使用脚本运行应用程序:

setenv DYLD_SHARED_REGION avoid
sudo dtrace -s objc-calls.d -c /Path/To/Your/App/Binary
Run Code Online (Sandbox Code Playgroud)

您还可以使用类似的dtrace探针构建自定义仪器.