https://www.cnblogs.com/chrisbin/articles/6486906.html
对象方法存在类对象中;类方法存在元类中
// 1.通过类创建对象
/*
1.开辟存储空间, 通过new方法创建对象会在堆 内存中开辟一块存储空间
2.初始化所有属性
3.返回指针地址
创建对象的时候返回的地址其实就是类的第0个属性的地址
但是需要注意的是: 类的第0个属性并不是我们编写的_age, 而是一个叫做isa的属性
isa是一个指针, 占8个字节
其实类也是一个对象, 也就意味着Person也是一个对象
平时我们所说的创建对象其实就是通过一个 类对象 来创建一个 新的对象
类对象是系统自动帮我们创建的, 里面保存了当前对象的所有方法
而实例对象是程序员自己手动通过new来创建的, 而实例对象中有一个isa指针就指向了创建它的那个类对象
*/
Person *p = [Person new];
p->_age = 30;
p->_height = 1.75;
p->_weight = 65.0;
[p walk];
[Person demo]
同一个类的不同对象的isa指针的地址是一样的,因为他们指向的是同一个类对象
程序一启动,会把Person类的代码加载到代码区,加载到代码区后,当第一次使用该类的时候内部会自动创建Person类对象及其方法列表,然后调用new方法后会通过Person类对象创建一个Person实例对象,然后给Person的所有属性都初始化为0,并且会初始化一个isa指针并指向Person类对象,当调用p->_age = 30;会通过实例对象直接修改_age的值,当调用[p walk]对象方法时,会通过栈中的p所指向的存储空间,由于存储空间中并没有存储方法,所以会通过isa指针找到实例对象对应的Person类对象,然后在类对象的方法列表中找到walk方法并执行.当执行[Person demo]类方法时,会直接去内存中找到Person这个类对象,找到之后再去方法列表中找demo这个方法,找到就执行(类对象中存储实例变量和对象方法,元类对象中存储类方法)
因为类也是一个对象,那它也必须是另一个类的实例,这个类就是元类 (metaclass)。
元类保存了类方法的列表。当一个类方法被调用时,元类会首先查找它本身是否有该类方法的实现,如果没有则该元类会向它的父类查找该方法,直到一直找到继承链的头。
元类(metaclass)也是一个对象,那么元类的isa指针又指向哪里呢?为了设计上的完整,所有的元类的isa指针都会指向一个根元类(root metaclass)。
根元类(root metaclass)本身的isa指针指向自己,这样就行成了一个闭环。上面说到,一个对象能够接收的消息列表是保存在它所对应的类中的。在实际编程中,我们几乎不会遇到向元类发消息的情况,那它的isa 指针在实际上很少用到。不过这么设计保证了面向对象的干净,即所有事物都是对象,都有isa指针。
由于类方法的定义是保存在元类(metaclass)中,而方法调用的规则是,如果该类没有一个方法的实现,则向它的父类继续查找。所以为了保证父类的类方法可以在子类中可以被调用,所以子类的元类会继承父类的元类,换而言之,类对象和元类对象有着同样的继承关系。
下面这张图或许能够 让大家对isa和继承的关系清楚一些
上图中,最让人困惑的莫过于Root Class了。在实现中,Root Class是指 NSObject,我们可以从图中看出:
NSObject类对象包括它的对象实例方法。
NSObject的元对象包括它的类方法,例如new方法。
NSObject的元对象继承自NSObject类。
一个NSObject的类中的方法同时也会被NSObject的子类在查找方法时找到。