RunTime回顾

前些日工作闲暇时间又看了一遍 南峰子关于RunTime的博客,为了以后查阅方便,还是决定咬牙自己总结一下。

一、类和对象
1.Class

Objective-C类是Class类型的,它实际上是一个指向objc_class结构体的指针。它的定义如下:

Class aClass = NSClassFromString(@"NSString");
typedef struct objc_class *Class;

objc_class结构体的定义如下:

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;                      // isa指针(指向MetaClass)
#if !__OBJC2__
    Class _Nullable super_class                                  OBJC2_UNAVAILABLE;   // 父类
    const char * _Nonnull name                                   OBJC2_UNAVAILABLE;   // 类名
    long version                                                 OBJC2_UNAVAILABLE;   // 类的版本信息,默认为0
    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;

在Class的定义中,下面几个字段是我们感兴趣的

  • isa : OC中所有的类自身也是一个对象,Class里的isa指针指向它的metaClass(元类)。
  • super_class: 指向该类的父类,如果是根类(NSObject、NSProxy),则super_class为NULL。
  • cache: 用于缓存使用过的方法,防止每次调用方法都去methodLists中查找,提高调用效率。
2.实例对象

OC定义对象时,Person *aPerson;Person是Class对象,即objc_class结构体的指针。objc/objc.h类中,定义Class的同时,定义了objc_object的结构体和id,那aPerson是objc_object结构体的指针。

#if !OBJC_TYPES_DEFINED
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

/// A pointer to an instance of a class.
typedef struct objc_object *id;
#endif

实例化对象的过程

Person *aPerson = [[Person alloc]init];
  1. Person调用 +alloc方法,因为Person没有实现+alloc方法,所以去super_class(Person继承自NSObject,所以这里super_class是NSObject)查找。
  2. 直到响应+alloc方法,检测Person类,根据所需申请一段内存空间,使用函数class_createInstance来创建一个objc_object,并把isa指针指向Person类。同时+alloc被添加到cache列表里。
  3. 接着执行-init方法,如果Person响应了-init方法,直接将其加入cache表,如果不响应,就去父类中查找,同+alloc
3.objc_cache

objc_cache的定义如下:

struct objc_cache {
    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;
    unsigned int occupied                                    OBJC2_UNAVAILABLE;
    Method buckets[1]                                        OBJC2_UNAVAILABLE;
};
4.元类

OC中类本身也是一个对象,那objc_class的isa指向谁呢?没错,就是元类metaClass,元类的objc_method_list存储了类方法.


isa指针.jpg
5.类与对象操作函数

runtime提供了大量的函数来操作类与对象。
①类操作方法 (class_开头)

//****************************************
                   **内省**
****************************************//
// 判断给定的Class是否是一个元类
BOOL class_isMetaClass(Class cls);
// 响应方法判断
BOOL class_respondsToSelector (Class cls, SEL sel);
// 遵循协议
BOOL class_conformsToProtocol (Class cls, Protocol *protocol);

//****************************************
                   **get**
****************************************//
// 获取类的类名
const char *class_getName(Class cls);
// 获取类的父类 Ps:cls为Nil或者为根类时,返回Nil
Class class_getSuperClass(Class cls);
// 获取实例的大小
size_t class_getInstanceSize(Class cls);
// 获取指定名称的成员变量的信息
Ivar class_getInstanceVariable(Class cls, const char *name);
// 获取类成员变量 ( 目前OC中未找到类变量)
Ivar class_getClassVariable (Class cls,const char *name);
// 获取指定的属性
objc_property_t class_getProperty (Class cls,const char *name);
// 获取实例方法
Method  class_getInstanceMethod (Class cls,SEL name);
// 获取类方法
Method class_getClassMethod (Class cls,SEL name);
// 获取方法的具体实现
IMP class_getMethodImplementation (Class cls,SEL name);
IMP class_getMethodImplementation_stret (Class cls, SEL name);

//****************************************
                   **copy**
****************************************//
/***  成员变量列表、属性列表、方法列表、协议列表  ***/
Ivar * class_copyIvarList (Class cls, unsigned int *outCount);
objc_property_t * class_copyPropertyList (Class cls, unsigned int *outCount);
Method * class_copyMethodList (Class cls,unsigned int *outCount);
Protocol * class_copyProtocolList (Class cls,unsigned int *outCount); 
// 注:这4个方法获取的对象要free()掉
//****************************************
                   **add**
****************************************//
// 添加成员变量,参数说明:添加的类、成员变量名、成员变量大小、偏移量、类型
BOOL class_addIvar (Class cls,const char *name,size_t size,uint8_t alignment,const char *types);
// eg:class_addIvar(cls, "_ivar1", sizeof(NSString *), log(sizeof(NSString *)), "i");
// 注:OC不能为已存在的类添加成员变量,动态创建的类才能添加,且必须在objc_allocateClassPair和objc_registerClassPair之间调用。
// 添加属性
BOOL class_addProperty (Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount);
// eg :   objc_property_attribute_t type = {"T", "@\"NSString\""};
          objc_property_attribute_t ownership = { "C", "" };
          objc_property_attribute_t backingivar = { "V", "_ivar1"};
          objc_property_attribute_t attrs[] = {type, ownership, backingivar};
          class_addProperty(cls, "property2", attrs, 3);
// 添加方法
BOOL class_addMethod (Class cls,SEL name,IMP imp,const char *types);
// eg :   class_addMethod(cls, @selector(submethod1), (IMP)imp_submethod1, "v@:");
// 添加协议
BOOL class_addProtocol (Class cls, Protocol *protocol);

//****************************************
                 **replace**
****************************************//
// 替换类的属性
void class_replaceProperty (Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
// 替换方法的实现
IMP class_replaceMethod (Class cls, SEL name, IMP imp, const char *types);

②实例对象操作方法(objc_ 、 object_)

//****************************************
                  **get**
****************************************//
// 获取对象实例变量 (ARC 多用object_getIvar,效率比getInstanceVariable快)
Ivar object_getInstanceVariable(id obj, const char *name, void **outValue);
// 获取对象中实例变量的值
id object_getIvar(id obj, Ivar ivar);
// 获取对象的类名
const char * object_getClassName(id obj);
// 获取对象的类
Class object_getClass(id obj);
Class objc_getClass(const char *name);
// 返回指定类的元类
Class objc_getMetaClass(const char *name);
// 获取关联对象, get方法
id objc_getAssociatedObject(self,&myKey);

//****************************************
                  **copy**
****************************************//
// 创建并返回一个指向所有已注册类定义的指针列表
Class * objc_copyClassList(unsigned int * _Nullable outCount);
// 返回所有已加载的OC框架和动态库列表
const char ** objc_copyImageNames(unsigned int * _Nullable outCount);
// 返回运行时已知的所有协议的数组
Protocol * _Nonnull * objc_copyProtocolList(unsigned int *outCount);
// 返回指定框架包含的所有类名数组
const char * _Nonnull * objc_copyClassNamesForImage(const char *image, unsigned int *outCount);

//****************************************
                  **set**
****************************************//
// 为指定成员变量赋值
void object_setIvar(id obj, Ivar ivar, id value);
// 为某个成员变量绑定类
Class object_setClass(id obj, Class cls);
// 给指定对象设置一个关联值
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);

//****************************************
             **类、对象创建及销毁**
****************************************//
// 释放指定对象占用的内存
id object_dispose(id obj);
// 创建一个新类和元类
Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes);
// 销毁一个类及其相关联的类
void objc_disposeClassPair(Class cls);
// 注册objc_allocateClassPair创建的类
void objc_registerClassPair(Class cls);
// 创建实例类
id class_createInstance(Class cls, size_t extraBytes);
// 在指定位置创建实例
id objc_constructInstance(Class cls, void *bytes);
// 销毁类实例
void * objc_destructInstance(id obj);

写到一半,遇到问题需要验证、、、 哈哈哈哈哈哈

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343