在方法中获取参数类型

时间:2011-07-16 02:04:59

标签: iphone objective-c cocoa

我正在尝试子类化某个类并覆盖它的一些私有方法。这很危险,可能会失败,无法通过Apple的评论(在AppStore中),可能会产生可怕的影响等,但这只是出于实验/教育目的:)

例如,假设我想知道keyboardInput:shouldInsertText:isMarkedText:的实例方法UITextView的第一个参数的类型:

SEL selector = @selector(keyboardInput:shouldInsertText:isMarkedText:);
Class class = [UITextView class];
Method method = class_getInstanceMethod(class, selector);
char *arg = method_copyArgumentType(method, 0);
printf("_%s_\n", arg);
free(arg);

但是在控制台中我只得到_@_。 我认为@意味着对象但是什么类的对象? (我以为我会得到参数类的名称)是否可以使用其他objective-c runtime functions或任何其他方法来获取该参数的类?

PS:在示例中,我使用了一类Cocoa touch,但我可以尝试使用一类Cocoa完全相同。所以这不应该是iOS特有的。

解决:

我已经在模拟器中尝试了Dave的建议,它有效!

(gdb) info all-registers给了我一长串价值观,......

((gdb) po *(id*)($ebp + 8)
<MyTextView: 0x5911270; baseClass = UITextView; frame = (80 70; 240 323); text = 'Lorem ipsum dolor sit er ...'; clipsToBounds = YES; autoresize = RM+BM; layer = <CALayer: 0x5c0c7d0>; contentOffset: {0, 0}>

(gdb) p *(SEL*)($ebp + 12)
$5 = (SEL) 0xbd19

(gdb) po *(id*)($ebp + 16)
<UIWebDocumentView: 0xa02f000; frame = (0 0; 240 457); text = 'Lorem ipsum dolor sit er ...'; opaque = NO; userInteractionEnabled = NO; layer = <UIWebLayer: 0x5c35070>>

(gdb) po *(id*)($ebp + 20)
t

(gdb) p *(id*)($ebp + 24)
$6 = (id) 0x0

这是有道理的,因为我按下的键是单个“t”所以它没有标记文本(“0x0”)所以我可以认为第一个参数应该是UIWebDocumentView类型。

只是一件小事(在这种情况下无关紧要),我如何从gbd中的SEL获取方法名称?例如$5

3 个答案:

答案 0 :(得分:9)

你不能从界面的内省中告诉类的参数。一旦编译完成,所有id在Objective-C中都是相同的。但是,您可以向特定实例询问-class。因此,如果您正在尝试对内部方法进行反向工程,则需要调整方法,调用它,然后内省您传递的对象。关于如何将代码注入任何Objective-C方法的大量讨论,谷歌“方法调整”。

答案 1 :(得分:6)

假设这仅适用于学术兴趣 ....

您可以找到的一种方法是在GDB中打破符号并检查参数。您知道它们是什么一般类型(即float vs object等),因此您只需使用正确的p命令即可​​打印它们。 / p>

要设置断点,您可以执行以下操作:

  1. 在gdb控制台中,键入b -[UITextView keyboardInput:shouldInsertText:isMarkedText:]
  2. 在Xcode中,为-[UITextView keyboardInput:shouldInsertText:isMarkedText:]
  3. 添加新的符号断点

    当你真正点击断点时,你不会看到任何有用的东西(当然)。但是你可以在这一点上打印参数,因为你知道它们的大小,因此它们应该在寄存器中。

    有关他们所在的寄存器的更多信息,请查看this handy blog post。您还可以执行info all-registers之类的操作来打印所有寄存器中的所有信息等。


    <强>更新

    如果你想打印选择器的名称,你可以使用一个小技巧,即选择器或多或少* char* s:

    p (char*)$5
    

    将打印:

    ${some number} = 0x{some address} "keyboardInput:shouldInsertText:isMarkedText:"
    

答案 2 :(得分:0)

@确实意味着“对象”,但你无法找到它是什么类。这不会保存在二进制文件的__OBJC段中,因此除非您拥有原始头文件,否则无法使用。

你必须猜测它。 :)