在面向对象的语言中,类和对象是我们接触最多的东西,那么在iOS中类和对象到底是什么样的?方法调用是怎么实现的?标题为Runtime
,跟类和对象有什么关系呢?不要着急,跟着我的思路,开始认识iOS中类和对象的本质。
首先我们在
中找到如下定义:
typedef struct objc_class *Class;
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
在
中找到如下定义:
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
结合起来不难发现,类其实是就是一个指向结构体的指针,而对象其实就是一个指向struct objc_object
的指针,它里面的isa
指针指向他的类对象,引用网络上的一个图
通过这个图我们先大概的理解一下,
对象```的```isa```指向其```类(或者叫类对象)```,```类
的isa
指向元类
,而元类的isa
指向根元类
,根元类
的isa
则指向自身
但是这张图仅仅是理论,那么实际是什么样子的呢?
Talk is cheap. Show me the code
废话不多说,上代码:
/**=======================================*/
@interface GrandFather:NSObject
@end
@implementation GrandFather
@end
/**=======================================*/
@interface Father:GrandFather
@end
@implementation Father
@end
/**=======================================*/
@interface Son:Father
@end
@implementation Son
@end
接下来我们来打印下细节(为了更加清晰,没有使用循环)
Son *son = [[Son alloc] init];
Class sonISA = object_getClass(son);
Class sonClass = [sonISA class];
Class sonClassISA = object_getClass(sonClass);
Class sonClassClass = [sonClassISA class];
Class sonClassClassISA = object_getClass(sonClassClass);
Class sonClassClassClass = [sonClassClassISA class];
Class sonClassClassClassISA = object_getClass(sonClassClassClass);
Class sonClassClassClassClass = [sonClassClassClassISA class];
NSLog(@"============Son Info============");
NSLog(@"Son instance address:%p",son);
NSLog(@"Son instance isa:%@------%p",NSStringFromClass(sonISA),sonISA);
NSLog(@"Son Class:%@------%p",NSStringFromClass(sonClass),sonClass);
NSLog(@"%@",class_isMetaClass(sonClass)?@"元类":@"非元类");
NSLog(@"Son Class isa:%@------%p",NSStringFromClass(sonClassISA),sonClassISA);
NSLog(@"Son Class Class:%@------%p",NSStringFromClass(sonClassClass),sonClassClass);
NSLog(@"%@",class_isMetaClass(sonClassClass)?@"元类":@"非元类");
NSLog(@"Son Class Class isa:%@------%p",NSStringFromClass(sonClassClassISA),sonClassClassISA);
NSLog(@"Son Class Class Class:%@------%p",NSStringFromClass(sonClassClassClass),sonClassClassClass);
NSLog(@"%@",class_isMetaClass(sonClassClassClass)?@"元类":@"非元类");
NSLog(@"Son Class Class Class isa:%@------%p",NSStringFromClass(sonClassClassClassISA),sonClassClassClassISA);
NSLog(@"Son Class Class Class Class:%@------%p",NSStringFromClass(sonClassClassClassClass),sonClassClassClassClass);
NSLog(@"%@",class_isMetaClass(sonClassClassClassClass)?@"元类":@"非元类");
Father *father = [[Father alloc] init];
Class fatherISA = object_getClass(father);
Class fatherClass = [fatherISA class];
Class fatherClassISA = object_getClass(fatherClass);
Class fatherClassClass = [fatherClassISA class];
Class fatherClassClassISA = object_getClass(fatherClassClass);
Class fatherClassClassClass = [fatherClassClassISA class];
Class fatherClassClassClassISA = object_getClass(fatherClassClassClass);
Class fatherClassClassClassClass = [fatherClassClassClassISA class];
NSLog(@"============Father Info============");
NSLog(@"Father instance address:%p",father);
NSLog(@"Father instance isa:%@------%p",NSStringFromClass(fatherISA),fatherISA);
NSLog(@"Father Class:%@------%p",NSStringFromClass(fatherClass),fatherClass);
NSLog(@"%@",class_isMetaClass(fatherClass)?@"元类":@"非元类");
NSLog(@"Father Class isa:%@------%p",NSStringFromClass(fatherClassISA),fatherClassISA);
NSLog(@"Father Class Class:%@------%p",NSStringFromClass(fatherClassClass),fatherClassClass);
NSLog(@"%@",class_isMetaClass(fatherClassClass)?@"元类":@"非元类");
NSLog(@"Father Class Class isa:%@------%p",NSStringFromClass(fatherClassClassISA),fatherClassClassISA);
NSLog(@"Father Class Class Class:%@------%p",NSStringFromClass(fatherClassClassClassClass),fatherClassClassClassClass);
NSLog(@"%@",class_isMetaClass(fatherClassClassClassClass)?@"元类":@"非元类");
NSLog(@"Father Class Class Class isa:%@------%p",NSStringFromClass(fatherClassClassClassISA),fatherClassClassClassISA);
NSLog(@"Father Class Class Class Class:%@------%p",NSStringFromClass(fatherClassClassClassClass),fatherClassClassClassClass);
NSLog(@"%@",class_isMetaClass(fatherClassClassClassClass)?@"元类":@"非元类");
GrandFather *grandFather = [[GrandFather alloc] init];
Class grandFatherISA = object_getClass(grandFather);
Class grandFatherClass = [grandFatherISA class];
Class grandFatherClassISA = object_getClass(grandFatherClass);
Class grandFatherClassClass = [grandFatherClassISA class];
Class grandFatherClassClassISA = object_getClass(grandFatherClassClass);
Class grandFatherClassClassClass = [grandFatherClassClassISA class];
Class grandFatherClassClassClassISA = object_getClass(grandFatherClassClassClass);
Class grandFatherClassClassClassClass = [grandFatherClassClassClassISA class];
NSLog(@"============GrandFather Info============");
NSLog(@"GrandFather instance address:%p",grandFather);
NSLog(@"GrandFather instance isa:%@------%p",NSStringFromClass(grandFatherISA),grandFatherISA);
NSLog(@"GrandFather Class:%@------%p",NSStringFromClass(grandFatherClass),grandFatherClass);
NSLog(@"%@",class_isMetaClass(grandFatherClass)?@"元类":@"非元类");
NSLog(@"GrandFather Class isa:%@------%p",NSStringFromClass(grandFatherClassISA),grandFatherClassISA);
NSLog(@"GrandFather Class Class:%@------%p",NSStringFromClass(grandFatherClassClass),grandFatherClassClass);
NSLog(@"%@",class_isMetaClass(grandFatherClassClass)?@"元类":@"非元类");
NSLog(@"GrandFather Class Class isa:%@------%p",NSStringFromClass(grandFatherClassClassISA),grandFatherClassClassISA);
NSLog(@"GrandFather Class Class Class:%@------%p",NSStringFromClass(grandFatherClassClassClass),grandFatherClassClassClass);
NSLog(@"%@",class_isMetaClass(grandFatherClassClassClass)?@"元类":@"非元类");
NSLog(@"GrandFather Class Class Class isa:%@------%p",NSStringFromClass(grandFatherClassClassClassISA),grandFatherClassClassClassISA);
NSLog(@"GrandFather Class Class Class Class:%@------%p",NSStringFromClass(grandFatherClassClassClassClass),grandFatherClassClassClassClass);
NSLog(@"%@",class_isMetaClass(grandFatherClassClassClassClass)?@"元类":@"非元类");
在这里,我们分别创建了son
、father
、grandFather
三个对象,并且分别打印了对象的地址
,对象的isa指向的Class的地址
,类(类对象)的地址
等,结果如下
============Son Info============
Son instance address:0x60c00002c980
Son instance isa:Son------0x104d614a0
Son Class:Son------0x104d614a0
非元类
Son Class isa:Son------0x104d61478
Son Class Class:Son------0x104d61478
元类
Son Class Class isa:NSObject------0x105d0de58
Son Class Class Class:NSObject------0x105d0de58
元类
Son Class Class Class isa:NSObject------0x105d0de58
Son Class Class Class Class:NSObject------0x105d0de58
元类
============Father Info============
Father instance address:0x60c000003e40
Father instance isa:Father------0x104d61450
Father Class:Father------0x104d61450
非元类
Father Class isa:Father------0x104d61428
Father Class Class:Father------0x104d61428
元类
Father Class Class isa:NSObject------0x105d0de58
Father Class Class Class:NSObject------0x105d0de58
元类
Father Class Class Class isa:NSObject------0x105d0de58
Father Class Class Class Class:NSObject------0x105d0de58
元类
============GrandFather Info============
GrandFather instance address:0x60c000003de0
GrandFather instance isa:GrandFather------0x104d61400
GrandFather Class:GrandFather------0x104d61400
非元类
GrandFather Class isa:GrandFather------0x104d613d8
GrandFather Class Class:GrandFather------0x104d613d8
元类
GrandFather Class Class isa:NSObject------0x105d0de58
GrandFather Class Class Class:NSObject------0x105d0de58
元类
GrandFather Class Class Class isa:NSObject------0x105d0de58
GrandFather Class Class Class Class:NSObject------0x105d0de58
元类
这个结果和我们上面的图基本就可以对应起来了:
对象的isa指向类(或者叫类对象)
类的isa指向元类
元类的isa指向根元类
根元类的isa指向自身
那么什么是元类呢?
通过上面的描述,我们知道,其实类自身也是一个对象,那么类对象为什么能够调用方法呢?这里我们就要提一下方法调用的流程了
通过对象的isa指针找到他的类
在类的method list中查找方法
如果没有找到该方法,继续前往父类中查找
直到查找到该方法,才去执行方法
所以,类对象调用方法的也会去通过它的isa
查找它所属的类,也就是所谓的元类。
好,接下来我们来分析一下objc_class
里面的各个成员
objc_class -> isa
这个isa用来指向其所属的类
objc_class -> super_class
super_class用来指向其父类
objc_class -> name
类的名称
objc_class -> version
类的版本
objc_class -> info
类的信息
objc_class -> instance_size
实例的大小
objc_class -> ivars
实例变量列表
objc_class -> methodLists
方法列表,我们看下Method
在OC
里的结构
typedef struct objc_method *Method;
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
里面包含了SEL
、method_type
、IMP
objc_class -> cache
缓存列表
objc_class -> protocols
协议列表