奇技淫巧 指过于奇巧而无益的技艺与制品.
先来看一段代码
// A.h
- (void)funa
{
[b funB];
}
// b.h
-(void)funB
{
// 我在这里如何得到调用对象b的对象a呢
}
有的时候底层就是想知道高层,别纠结什么时候,这个主题下的文章注定都是这个德行的.我们又不想把a传给b.那么有办法的到a么,答案肯定是有的.
方法在调用的过程中呢,会有个压栈的过程,oc下栈里的东西按照高位到地位排序为:
1 self对象 2 方法sel 3 参数… 4变量…
在方法funb构造一个变量,然后地址 加加 就获得了方法funB了,再 加加 就获得b对象了
-(void)funB
{
int a = 999;
int *obj = &a + 2;
SEL *sel = &a + 1;
NSLog(@"%s, a %p", __FUNCTION__, &a);
NSLog(@"%s, obj %p", __FUNCTION__, obj);
NSLog(@"%s, sel %p", __FUNCTION__, sel);
NSLog(@"%@", *obj);
NSString *str2 = NSStringFromSelector(*sel);
NSLog(@"%@", str2);
}
这个时候如果我们在–会发生什么事情呢?当我们在 加加加 的时候,我们就进入到方法funa用到的栈的地址了,我们可以得到funa里的局部变量,这种情况下再 加加 就可以得到a了.整理下思路就是:
1 获取堆栈信息
2 将funa当作锚点
3 funa的地址 加加 就是对象a
// a.h
-(void)funA
{
NSLog(@"%s", __FUNCTION__);
}
- (IBAction)click2:(id)sender {
[_test funB];
}
// b.h
-(void)funB
{
int a = 999;
id b = @"bbbb";
NSString *name = [CallStack preSelName];
// NSLog(@"%@", name);
NSString *clazz = [CallStack preSelName];
// NSLog(@"%@", clazz);
SEL *preSel = &a + 1;
int i = 0;
SEL *sel = &a + 1;
NSString *str2 = NSStringFromSelector(*sel);
NSString *selName = NSStringFromSelector(*preSel);
while (![name isEqualToString:selName])
{
i++;
preSel = &a + i;
selName = NSStringFromSelector(*preSel);
if (selName)
{
// NSLog(@"preSel: %p %@", *preSel, selName);
}
}
// NSLog(@"%@", selName);
int *preClazz = *(preSel + 1);
// NSLog(@"%@", preClazz);
id objc= (__bridge id)((void *)(preClazz));
NSLog(@"%@", objc);
[objc performSelector:@selector(funA) withObject:nil];
}
运行的结果是
2015-03-24 21:13:51.629 testaddress[12616:2623719] -[FirstViewController funA]
底层的b在不知道高层a的情况下,调用a的方法funA.
demo请看
https://github.com/uxyheaven/demo_testaddress
里的Button2
原文:http://blog.csdn.net/uxyheaven/article/details/44598781