最近一直在了解关于oc的类的知识,之前了解到的类都是在一个很浅显的层面上;
生活中的类无处不在,名词即为类,举个例子,Person为一个类,然后Person里有好多的属性,例如:_name,_age;
面向对象是从类中衍生出来的思维,有了它,我们可以很方便的看到结果,只论结果,不论过程;
例如:下面是通过面向对象的思维,通过类的方法,调用Person类的行为;
对于Person*p=[Person new];我一开的理解只是知道[Person new]是在内存中开辟了一个空间,用来存储我们的属性列表,以及我们的方法列表,具体里面是怎么开辟的,我了解得并不多,然后昨天时间比较多,而且机会比较好,我就详细的研究了一下,最后恍然大悟,因此想写下这篇博客和大家共勉。
首先看类的本质:类的本质是一个结构体指针!
Class是类的类型,Class cp就是定义了一个类类型的变量cp,[p class]是对象p的方法调用,调用[p class]方法的作用是将类在内存中的数据保存起来,然后将数据赋值给 cp,如下图。
对Class进一步探索发现,类类型实际是一个指针。
Class实际只是struct objc_class* 的别名;
class实际就是上图中的结构体。
类编译时在内存中开辟的空间详析
为了方便阅读,我画了个图
首先:1.在调用Person* p=[Person new]时会先在全局区中开辟一个空间,用来保存Class的对象,即类的模板;
(特别注意:里面有个SEL的方法的类型,会指向在代码区里的方法的实现)
2.然后在堆区里开辟空间,用来存储类模板里的属性列表,以及方法列表;最后有个isa用来指向在全局区里的Class的对象(类的模板);
3.在栈区开辟了指针p这个局部变量,用来指向在堆区里的属性列表等等;
当我们通过对象调用方法的时候,会先将方法封装为SEL类型,然后通过各类指针指向我们的全局区,最后和全局区里的方法的SEL类型进行比对,比对成功,则进入代码区进行代码的实现,比对不成功则报错;
注:以上步骤的排序不代表在内存里开辟空间的先后顺序;
补充:在我们调用self 和super方法时,会有调用父类还是自己本身类方法的选择,在全局区里方法的SEL类型里有自己的方法,还有继承而来的父类方法,当用self时,会告诉系统,此时在全局区里调用的是自己的方法,用super时则是调用父类的方法。