iOS 底层强行调用高层接口

iOS 底层强行调用高层接口

奇技yin巧 指过于奇巧而无益的技艺与制品.

转载请注明出处http://blog.csdn.net/uxyheaven?viewmode=contents
系列文章请看http://blog.csdn.net/uxyheaven/article/category/5800569

先来看一段代码

// 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);

    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

你可能感兴趣的:(IOS开发,iOS奇技yin巧)