美文网首页iOS底层
iOS-内存地址调用

iOS-内存地址调用

作者: xxxxxxxx_123 | 来源:发表于2020-02-26 20:40 被阅读0次

    下面程序是否能够执行?为什么?

    @interface TPerson : NSObject
    
    - (void)eat;
    
    @end
    
    @implementation TPerson
    
    - (void)eat {
        NSLog(@"==TPerson==eat====");
    }
    
    
    @end
    
    TPerson *person = [[TPerson alloc] init];
    [person eat];
        
    id pcls = [TPerson class];
    void *pp= &pcls;
    [(__bridge id)pp eat];
    

    解析,运行程序,控制台输出:

    2020-02-21 17:46:54.530375+0800 005---Runtime应用[52965:2000889] ==TPerson==eat====
    2020-02-21 17:46:54.530576+0800 005---Runtime应用[52965:2000889] ==TPerson==eat====
    

    可以看到pp确实正常调用了方法,这是为什么呢?我们先来分析一下,person调用方法,person是一个对象,而对象的本质是个结构体,并且第一个元素是isaisa指向的是类对象。实例方法都是存在类中的,person能够调用方法,也是通过isa指向了类,从而从类的数据中找到了方法。

    再来看看pclspcls指向的是TPerson的类对象,而指针pp又指向的是pcls的地址,这样也形成了一个指向关系:pp指向pcls,而pcls指向TPerson的类对象,也就可以正常调用方法了。

    我们给TPerson添加一个属性:

    @property (nonatomic, copy) NSString *name;
    

    eat的实现改成以下:

    - (void)eat {
        NSLog(@"==TPerson==eat=====name=%@==", self.name);
    }
    

    然后对代码做以下的修改:

    // TPerson *person = [[TPerson alloc] init];
    // [person eat];
    
    id pcls = [TPerson class];
    void *pp= &pcls;
    [(__bridge id)pp eat];
    

    运行程序,会发现控制台输出:

    2020-02-21 19:23:51.188431+0800 005---Runtime应用[53411:2043433] ==TPerson==eat=====name=<ViewController: 0x7ff70f400760>==
    

    这是为什么呢?然后我们上述注释的代码放开,运行程序,控制台输出:

    2020-02-21 19:33:30.325806+0800 005---Runtime应用[53472:2047490] ==TPerson==eat=====name=(null)==
    2020-02-21 19:33:30.326163+0800 005---Runtime应用[53472:2047490] ==TPerson==eat=====name=<TPerson: 0x60000129c700>==
    

    在程序运行期间,执行代码就会不停的压栈-出栈操作。由于栈的地址是连续的,pp又是pcls的地址。第一次的时候,由于先调用[super viewDidLoad],我们的栈里已经压入了ViewController,当执行[(__bridge id)pp eat]的时候,需要获取self.name的值,而name占用8字节,由于name本身还没有初始化,也没有值,pp地址偏移8字节就会获取到之前压入栈里的ViewController。同理加入TPerson之后,偏移8字节获取到了TPerson

    Tips: & 和 *

    *是取值运算符,对地址使用可以获得地址中储存的数值。对于指针a*a表示取a中的值。

    在调用时,*p是指针p指向的那个变量,比如:

    int a = 5;
    int *p = a;
    

    那么p的值是a的地址,也就是指针p指向a*p则等于a的值,即*p=5

    &是地址运算符,对变量使用可以获得该变量的地址。 对于变量b&b表示取b的地址。

    &是引用,比如:

    int a = 5;
    int b = &a;
    

    那么这里的b则引用a的值,即b=5,而再给b赋值:b=10a的值也会变为10。

    相关文章

      网友评论

        本文标题:iOS-内存地址调用

        本文链接:https://www.haomeiwen.com/subject/jvpwchtx.html