美文网首页
『ios』来自isa super方法调用的一份问答

『ios』来自isa super方法调用的一份问答

作者: butterflyer | 来源:发表于2021-07-09 17:01 被阅读0次

有些东西可能只有串到一起才能理解的更加深刻。
有这么一个person类

@interface XHPerson : NSObject
@property (copy, nonatomic) NSString *name;
- (void)print;
@end
@implementation XHPerson
- (void)print
{
    NSLog(@"my name is %@", self->_name);
}
@end

然后我们在viewController中这么写

@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
   NSString *test = @"123";
    id cls = [XHPerson class];
    void *obj = &cls;
    [(__bridge id)obj print];
}
@end

那么现在有这么两个问题
1.这个项目能否编译成功,为什么?
2.如果能调用成功,上面的print函数打印的结果是什么,为什么?

来看第一个问题,项目能否编译成功

看上面这个问题的时候,先来看下面这种情况。

XHPerson *person = [[XHPerson alloc] init];

struct XHPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *_name;
};
struct NSObject_IMPL {
    Class isa;
};

我们知道对象的本质是一个结构体。
所以我们可以得出**person对象 -> isa ->[XHPerson Class] **
我们再回头看

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

首先cls -> [XHPerson class],obj->cls.
那么obj -> cls -> [XHPerson class].
是不是跟上面的person对象的例子很像?
obj就像前面person对象,通过isa指针,去XHPerson类对象中去找对象方法print,肯定是可以找的到的。所以可以执行成功
就这样第一个问题解决了。

print打印的结果是什么?

栈空间是从高地址到低地址分配

- (void)print
{
    NSLog(@"my name is %@", self->_name);
}

要打印的 _name 成员变量,其实是通过self -> 去查找(每个方法都会有两个参数, self 和 _cmd),这里的self就是函数的调用者,[(__bridge id)obj print]是 obj 开始找,而找 _name ,是通过指针地址查找,找得XHPerson_IMPL 结构体,因为这里的 XHPerson_IMPL 里面就两个变量,所以这里查找 _name,就是通过 isa 的地址,跳过8个字节,找到 _name.


image.png

所以在controller里,test处于高地址,obj处于低地址。
person对象 -> isa ->[XHPerson Class]
obj -> cls -> [XHPerson class]
我们可以理解为cls == isa。person需要跳过isa找到name,obj需要跳过cls找到test。
所以输出为123.

如果去掉test这一行呢?

- (void)viewDidLoad {
    [super viewDidLoad];
    id cls = [XHPerson class];
    void *obj = &cls;
    [(__bridge id)obj print];
}

在这里正好就用到上一篇总结到的super调用方法的原理中的内容。

struct __rw_objc_super { 
    struct objc_object *object; 
    struct objc_object *superClass; 
    __rw_objc_super(struct objc_object *o, struct objc_object *s) : object(o), superClass(s) {} 
};

 ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ViewController"))}, sel_registerName("viewDidLoad"));

这里是存在一个objc_super的结构体。
栈是由高到底的内存地址分布,结构体由低到高

    struct abc = {
        self,
        [ViewController class]
    };
    objc_msgSendSuper2(abc, sel_registerName("viewDidLoad"));

就可以转换成下面的这种关系


image.png

我们可以理解为cls == isa。person需要跳过isa找到name,obj需要跳过cls找到的是self。
所以print打印的结果是viewcontroller

相关文章

网友评论

      本文标题:『ios』来自isa super方法调用的一份问答

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