我正在尝试子类化某个类并覆盖它的一些私有方法。这很危险,可能会失败,无法通过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
?
答案 0 :(得分:9)
你不能从界面的内省中告诉类的参数。一旦编译完成,所有id
在Objective-C中都是相同的。但是,您可以向特定实例询问-class
。因此,如果您正在尝试对内部方法进行反向工程,则需要调整方法,调用它,然后内省您传递的对象。关于如何将代码注入任何Objective-C方法的大量讨论,谷歌“方法调整”。
答案 1 :(得分:6)
假设这仅适用于学术兴趣 ....
您可以找到的一种方法是在GDB中打破符号并检查参数。您知道它们是什么一般类型(即float
vs object
等),因此您只需使用正确的p
命令即可打印它们。 / p>
要设置断点,您可以执行以下操作:
b -[UITextView keyboardInput:shouldInsertText:isMarkedText:]
-[UITextView keyboardInput:shouldInsertText:isMarkedText:]
当你真正点击断点时,你不会看到任何有用的东西(当然)。但是你可以在这一点上打印参数,因为你知道它们的大小,因此它们应该在寄存器中。
有关他们所在的寄存器的更多信息,请查看this handy blog post。您还可以执行info all-registers
之类的操作来打印所有寄存器中的所有信息等。
<强>更新强>
如果你想打印选择器的名称,你可以使用一个小技巧,即选择器或多或少* char*
s:
p (char*)$5
将打印:
${some number} = 0x{some address} "keyboardInput:shouldInsertText:isMarkedText:"
答案 2 :(得分:0)
@确实意味着“对象”,但你无法找到它是什么类。这不会保存在二进制文件的__OBJC段中,因此除非您拥有原始头文件,否则无法使用。
你必须猜测它。 :)