runtime-内存访问相关

2021-09-16  本文已影响0人  Berning

示例

#import "NSPerson.h"


@interface NSWorker : NSPerson

@property NSString *name;

- (void)print;

@end

#import "NSWorker.h"

@implementation NSWorker

- (void)person
{
    [super person];

    id cls = [self class];
    void *obj = &cls;
    [(__bridge id)obj print];
    
}

#import "NSWorker.h"

int main()
{
        [[NSWorker new] person];
}

//log
2020-08-28 20:10:31.537720+0800 runtime[9289:160822] my name is <NSWorker: 0x10071f120>
Program ended with exit code: 0

图示

示意图

分析1

对比上图两种方法调用方式,可以看出:
1>通过obj调用print: 是直接找到NSWorker类,然后调用print
2>通过worker调用print: 是通过worker对象内部的isa&isa_mask找到NSWorker类,然后调用print

结论,可以调用成功

分析2

两种方式的区别
1>obj调用print:局部变量obj与cls在函数栈空间是连续的,即局部变量obj与cls(NSWorker)内部isa内存地址是连续的
2>worker调用print:局部变量worker与函数栈空间其他局部变量是 连续的,worker 调用print是通过worker内部isa & isa_mask找到NSWorker类(isa),所以worker与NSWorker内部的isa的内存地址是不连续的

结论:print内部访问结构体NSWorker_IMPL的name成员,是访问其isa后面的8个字节
1>obj调用print:因为obj直接指向了cls = NSWorker_IMPL(isa),所以相当于访问cls后面8个字节,name的值是pls前面的那个局部变量的值
2>worker调用print:因为worker是间接指向NSWorker_IMPL,所以访问的8个字节的值不会是函数栈空间的其他局部变量

分析3

为什么输出结果是my name is <NSWorker: 0x10071f120>

- (void)person
{
    [super person];

    id cls = [self class];
    void *obj = &cls;
    [(__bridge id)obj print];
    
}

通过分析1和分析2
person方法内部的局部变量有:

obj 
cls
objc_super  objc_s = {self , [self class]};

上面三个地址由低到高,而obj = cls->isa,所以后面8个字节是objc_s的前8个字节,即self(当前对象)

上一篇下一篇

猜你喜欢

热点阅读