Runtime运行时一:类

简介

Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。

这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc RuntimeObjc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。

objc_object

objc_object是表示一个类的实例的结构体

struct objc_object {
    Class isa  OBJC_ISA_AVAILABILITY;
};
  • isa指针指向所属的类
    可以看到,这个结构体只有一个字体,即指向实例所属类的isa指针。当我们向一个Objective-C对象发送消息时,运行时库会根据实例对象的isa指针找到这个实例对象所属的类。Runtime库会在类的方法列表及父类的方法列表中去寻找与消息对应的selector指向的方法。找到后即运行这个方法。
Class

Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针,也就意味着Class本身也是一个对象。它的定义如下:

typedef struct objc_class *Class;
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父类
    const char *name                        OBJC2_UNAVAILABLE;  // 类名
    long version                            OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0
    long info                               OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识
    long instance_size                      OBJC2_UNAVAILABLE;  // 该类的实例变量大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 该类的成员变量链表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法缓存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表
#endif
} OBJC2_UNAVAILABLE;
  • isa指针指向Meta Class(元类)
    既然类也是对象,那么它也是一个objc_object指针,它包含一个指向其类的一个isa指针。那么这些就有一个问题了,这个isa指针指向什么呢?为了调用类方法,这个类的isa指针必须指向一个包含这些类方法的一个objc_class结构体。这就引出了Meta Class的概念
Meta Class

Meta Class是一个类对象的类,它存储着一个类的所有类方法。

  • isa指针指向基类Meta Class
    既然Meta Class也是一个类,也可以向它发送一个消息,那么它的isa又是指向什么呢?为了不让这种结构无限延伸下去,Objective-C的设计者让所有的Meta Classisa指向基类的Meta Class,以此作为它们的所属类。即任何NSObject继承体系下的Meta Class都使用NSObjectMeta Class作为自己的所属类,而基类的Meta Classisa指针是指向它自己。这样就形成了一个完美的闭环。

动态生成

既然Objective-C是一门动态语言,那么一切都可以在运行时动态创建。

创建类

参数一:父类
参数二:名称
参数三:开辟字节长度

Class Student = objc_allocateClassPair([Person class], "Student", 0);
创建成员变量

参数一:类名
参数二:名称
参数三:开辟字节长度
参数四:内存对齐方式
参数五:参数类型 “@” 官方解释 An object (whether statically typed or typed id) (对象 静态类型或者id类型) 具体类型可参照官方文档

class_addIvar(Student, "_studentID", sizeof(NSString *), log2(sizeof(NSString *)), "^NSString");
class_addIvar(Student, "_classNumber", sizeof(NSInteger), log(sizeof(NSInteger)), "i");
创建属性

属性类别说明

objc_property_attribute_t type = {"T", "@\"NSString\""}; // 类型
objc_property_attribute_t iver = {"V", "_studentID"}; // 绑定的成员变量
objc_property_attribute_t ownership = {"C", ""}; // 持有的参数
objc_property_attribute_t nonatomic = {"N", ""};// 原子量
        
objc_property_attribute_t attributes[] = {type, iver, ownership, nonatomic};
        
// 给一个类添加一个属性,@1 类名, @2: 属性明, @3:属性的参数说明数组
class_addProperty(Student, "sid", attributes, 4);
创建方法

参数一、类名
参数二、SEL 添加的方法名字
参数三、IMP指针 (IMP就是Implementation的缩写,它是指向一个方法实现的指针,每一个方法都有一个对应的IMP)
参数四、其中types参数为"i@:@“,按顺序分别表示:具体类型可参照官方文档
i 返回值类型int,若是v则表示void
@ 参数id(self)
: SEL(_cmd)
@ id(str)
V@:表示返回值是void 带有SEL参数 (An object (whether statically typed or typed id))

class_addMethod(Student, @selector(test:), (IMP)test, "v@:^NSString");

这里我们需要实现一个函数和一个方法

void test(id self, SEL _cmd, NSString *str) {
    // 实现写在这里
}

- (void)test:(NSString *)str {
    NSLog(@"%@", str);
}
创建对象

创建对象需要在系统注册

objc_registerClassPair(Student);

和创建成员变量方法一样,只是参数类型不一样

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

推荐阅读更多精彩内容