iOS底层

iOS-内存地址调用

2020-02-26  本文已影响0人  xxxxxxxx_123

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

@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。

上一篇下一篇

猜你喜欢

热点阅读