目录
- 概述
- 对象与类的实质
- id与class
- 继承关系与isa
- 总结
- C函数创建一个OC类
- OC类与runtime
- NSObjectProtocol
- NSObject
- NSProxy
Objective-C是开发 osx/ios 的主要语言,它是C语言的一个超集。Objective-C继承了C的基本语法特性,并添加了面对象的特性,所以在Objective-C代码里可以直接写C代码的。在Objective-C里面的对象是一个动态类型,只有在运行时才会被确定下来。在运行时你可以为一个类添加新的方法、属性,也可以修改这个类原有的方法、属性。提供动态添加、修改类的api我们管它叫做runtime api。这一篇文章我们就来学runtime api 、runtime与Objective-C的关系。Objective-C的runtime源码可以从这里获得 runtime 。每个版本的runtime实现不一样,本文以objc4-706.tar.gz为标板。
二、对象与类的实质
id与class
在Objective-C里面 id 代表着任意对象,Class代表着任意的类,我们可以看源码的定义:
typedef struct objc_class *Class; typedef struct objc_object *id;
可以看出id的实质是机构体objc_object的指针,Class的实质是结构体objc_class的指针。我们在查看结构体objc_object、objc_class的源码(隐藏了一些代码)
objc_object:
struct objc_object { private: isa_t isa; // 唯一的成员变量 代表当前对象所指向的类的信息 public:
// 返回isa的Calss指针
Class getIsa(); // 下面还有一系列相关的函数 ...... }
isa_t:
union isa_t { isa_t() { } isa_t(uintptr_t value) : bits(value) { } Class cls; uintptr_t bits; struct { uintptr_t nonpointer : 1; uintptr_t has_assoc : 1; uintptr_t has_cxx_dtor : 1; uintptr_t shiftcls : 33; // MACH_VM_MAX_ADDRESS 0x1000000000 uintptr_t magic : 6; uintptr_t weakly_referenced : 1; uintptr_t deallocating : 1; uintptr_t has_sidetable_rc : 1; uintptr_t extra_rc : 19; }; }
objc_class:
struct objc_class : objc_object { Class superclass; const char *name; uint32_t version; uint32_t info; uint32_t instance_size; struct old_ivar_list *ivars; struct old_method_list **methodLists; Cache cache; struct old_protocol_list *protocols; // CLS_EXT only const uint8_t *ivar_layout; struct old_class_ext *ext; // 下面还有一系列相关函数 ...... }
从上面我们可以看出2点
1.objc_object有一个成员变量isa用来保存这个对象指向的类的信息
2.objc_class继承objc_object,意思就是说class也是对象,我们管它叫做类对象
既然类对象也是对象,那么类对象自然也有isa成员变量了,oc里面把类对象的isa成员变量指向的类叫做元类(meta class)
元类是用来实现类方法的,那么元类对象的isa有指向什么呢?oc里面把元类对象的isa指向基类的元类。元类也是有父类...感觉无穷无尽了
我们还是来看图1吧:
我们来说明上图
1.Cat类继承Animal类,Animal类继承NSObject类,cat是Cat的一个实例
2.cat的对象的isa指向 Cat 类
3.Cat类的isa指向Cat类的元类(Cat meta class,相应的Animal类的isa指向Animal类的元类(Animal meta class),NSObject类的isa指向NSObject类的元类(NSObject meta class)
4.Cat类的元类继承Animal类的元类,Animal类的元类继承NSObject类的元类,NSObject类的元类继承NSObject类。
5.Cat meta class、Animal meta class、NSObject meta class这三个元类的isa都指向根元类(root metaclass)。大部分时候根元类就是NSObject meta class。
继承关系与isa
这些继承关系,还有isa构成了oc的对象与类整系统,它们到底怎么发生作用呢,请看下面例子。
@interface Animal : NSObject +(BOOL)isAnimal; // 是否动物 永远返回ture -(void)move; // 移动 @end @interface Cat :Animal -(void)eatFish; @end
上面是Cat与Animal类的实现,下面代码将展示对象、类怎么调用一个方法的。
Cat *cat = [Cat new]; [cat eatFish]; [cat move]; id newCat = [cat copy]; BOOL isAnimal = [Cat isAnimal];
首先是创建一个Cat的实例
Cat *cat = [Cat new];
分析上面这句代码前我们先确认一件事:实例方法是在类里实现的,类方法是在类的元类里实现的
确认了这些事,我们就可以开始分析了
1.因为new是类方法,所以第一步当然是查询Cat类的isa指向的Cat类的元类(Cat meta class)有没有这个方法,发现Cat meta class 并没有实现new方法。
2.接着查询Cat meta class的父类即Animal类的元类(Animal meta class)有没有这个方法,发现还是new方法。
3.再接着查询Animal meta class的父类既NSObject类的元类(NSObject meta class),发现NSObject meta class是有实现new方法的,所以就调用new方法返回一个实例cat。
[cat eatFish];
这句代码就比较简单了
先查询cat对象的isa指向的Cat类,有没有实现eatFish这个方法,发现Cat类已经实现了,直接调用既可。
[cat move];
这个跟[cat eatFish]类似,
1.先查询cat对象的isa指向的Cat类,发现并没有实现move方法
2.在查询Cat类的父类Animal类,发现Animal类已经实现了move,直接调用
id newCat = [cat copy];
这句代码与[cat move]类似
1.先查询cat对象的isa指向的Cat类,发现并没有实现copy方法
2.再查询Cat类的父类Animal类,发现并没有实现copy方法
3.继续查询Animal类的父类NSObject类,发现NSObject类有实现copy方法,直接调用
BOOL isAnimal = [Cat isAnimal];
这句代码与[Cat new]类似,大家可以试着分析。
总结
在Objectative-c里面一个类的实例是一个对象,一个类也是一个对象叫类对象,对象用结构体struct objc_objectl来描述,对象都有一个isa成员变量用来指向这个对象的类。对象实例的方法都走这个对象的类里实现。
类对象的isa指向这个类对象的类,类对象的类叫做元类。类的方法都在元类里实现。
元类它也是一个对象叫做元类对象。元类对象的isa指向根元类(root metaclass),根元类在大部分时候都是NSObject meta class。
当然,类的成员变量、属性、方法、协议等都由相应的机构体来表示,这里就不一一展开了,下文遇到会展开。
三、C函数创建一个OC类
这节我们用runtime的c函数来创建一个oc类,通过这种方式来加深对oc类的理解。
首先我写了一个方法用于打印一个id对象的类的相关信息,
1 void rtl_Class(id object){ 2 3 // 获取一个对象的class 4 Class cls = object_getClass(object); 5 // 获取class 名字 6 const char * className = class_getName(cls); 7 printf("%20s :[%p (%s)]\n" ,"class Name",cls,className); 8 9 // 展示类的继承关系 10 // 获取父类 11 Class superClass = class_getSuperclass(cls); 12 printf("%20s :[%p (%s)]" ,"class Inherit",cls,className); 13 while (superClass) { 14 printf(" => [%p (%s)]",superClass,class_getName(superClass)); 15 superClass = class_getSuperclass(superClass); 16 } 17 printf("\n"); 18 19 // 展示元类的继承关系 20 // 获取一个类的元类 21 Class metaClass = objc_getMetaClass(class_getName(cls)); 22 printf("%20s :[%p (%s)]" ,"meta class Inherit",metaClass,class_getName(metaClass)); 23 metaClass = class_getSuperclass(metaClass); 24 while (metaClass) { 25 printf(" => [%p (%s)]",metaClass, class_getName(metaClass)); 26 metaClass = class_getSuperclass(metaClass); 27 } 28 printf("\n"); 29 30 // 展示元类的isa信息 31 // isa成员变量在arm64下并不是一个Class的指针,所以不能直接这样使用 Class metaClass = cls->isa;但是可以打印cls->isa的指针 32 metaClass = objc_getMetaClass(class_getName(cls)); 33 while (metaClass) { 34 printf("%10s meta class isa :%p \n",class_getName(metaClass),metaClass->isa); 35 metaClass = class_getSuperclass(metaClass); 36 } 37 // 展示类变量列表 38 printf("\nvar List:\n"); 39 unsigned int count = 0; 40 Ivar * varList = class_copyIvarList(cls, &count); 41 for (int i=0; i<count; i++) { 42 Ivar var = varList[i]; 43 printf("[%30s] [offset:%ld]\n",ivar_getName(var),ivar_getOffset(var)); 44 } 45 // 展示属性列表 46 printf("\nproperty List:\n"); 47 count = 0; 48 objc_property_t * propList = class_copyPropertyList(cls, &count); 49 for (int i=0; i<count; i++) { 50 objc_property_t property = propList[i]; 51 printf("[%30s] [%s]\n",property_getName(property),property_getAttributes(property)); 52 } 53 54 // 展示类方法 55 printf("\nclass method List:\n"); 56 Class metaCls = objc_getMetaClass(class_getName(cls)); 57 count = 0; 58 Method * methodList = class_copyMethodList(metaCls, &count); 59 for (int i = 0; i < count; i++) { 60 Method method = methodList[i]; 61 printf("[%30s]\n",sel_getName(method_getName(method))); 62 } 63 64 // 展示实例类方法 65 printf("\nclass instance method List:\n"); 66 count = 0; 67 methodList = class_copyMethodList(cls, &count); 68 for (int i = 0; i < count; i++) { 69 Method method = methodList[i]; 70 printf("[%30s]\n",sel_getName(method_getName(method))); 71 } 72 printf("\n\n"); 73 }