Objective-C Runtimeの类与对象

2015-12-25  本文已影响33人  十一月三号

Objective-C是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这样处理也就意味着,它将使我们的代码更有灵活性。比如,我们可以根据我们的意向将消息转发给其它对象,或者去替换我们想要实现的方法等。因为Objective-C“动态化”的内容都是在运行时完成的,所以,OC的运行条件不仅仅要求有帮助我们向机器说话的编译器,还要有让代码随心而动的运行时,而这个运行时就是objc Runtime。它基本上是由C和汇编实现的,它让C具有了面向对象的能力

Runtime库主要做下面几件事:


类与对象

Objective-C是对C的进一步封装,让C有了面对对象的能力,为什么这么说呢,我们可以看一下下面的这个例子:

Person *per = [[Person alloc] init];

这是一个很简单的获取实例化对象的方法。
那么这个语句在经过编译后会变成什么样呢,想看的话我们可以这样做:

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic, assign) NSInteger age;

@end

@implementation Person

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p = [[Person alloc] init];
        p.age = 18;
        NSLog(@"%ld", p.age);
    }
    return 0;
}

int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ 
    { 
        __AtAutoreleasePool __autoreleasepool; 
        Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
        ((void (*)(id, SEL, NSInteger))(void *)objc_msgSend)((id)p, sel_registerName("setAge:"), (NSInteger)18);
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_dd_c58dp2w556l44jqlhxdgthdh0000gn_T_main_449954_mi_0, ((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("age")));
    }
    return 0;
}

在以上函数中,采用了消息发送机制,可以看到,OC在这里也脱去了它面向对象的外衣,显露除了些许本质。
以实例化对象p的初始化过程为例,简要分析一下其实现过程:
首先,在原文件中的

Person *p = [[Person alloc]init];

先后调用了两个方法,也即发送了两个消息, 对应的,编译后文件就是实现这一过程。

Person *(*)(id, SEL)(void *)objc_msgSend((id)objc_getClass("Person"), sel_registerName("alloc"));

这一方法对应的就是Person调用的alloc方法,objc_msgSend函数发送alloc消息(需要强转),它将会返回一个结构体(Person的实例化对象)。同理,返回的对象在执行初始化方法init时,需要再次发送消息,也就有了在.cpp文件中我们看到的样子:

Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));

*注:在.m中如果也想如此实现,需要引用<objc/runtime.h>和<objc/message.h>


数据结构

Class

Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。
查看objc/runtime.h中objc_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;

MetaClass

在objc_class的结构体中有isa这么一个字段,在Objective-C中,所有的类自身也是一个对象,这个对象的Class里面也有一个isa指针,它指向metaClass(元类)。
当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的meta-class的方法列表中查找。
meta-class之所以重要,是因为它存储着一个类的所有类方法。每个类都会有一个单独的meta-class,因为每个类的类方法基本不可能完全相同。
再深入一下,meta-class也是一个类,也可以向它发送一个消息,那么它的isa又是指向什么呢?为了不让这种结构无限延伸下去,Objective-C的设计者让所有的meta-class的isa指向基类的meta-class,以此作为它们的所属类。即,任何NSObject继承体系下的meta-class都使用NSObject的meta-class作为自己的所属类,而基类的meta-class的isa指针是指向它自己。这样就形成了一个完美的闭环。
通过上面的描述,再加上对objc_class结构体中super_class指针的分析,我们就可以描绘出类及相应meta-class类的一个继承体系了,如下图所示:

继承关系Class与Meta
我是这样去理解这个图的:
图中的各个类的关系以及isa指向就如同一个老亚家的家谱以及财产关系,首先图中的subClass可以看做是以诺, 他管理着一个村落中的所有兵器(instance of Class的方法),当村民需要使用时,需要问自己的村长有没有,并在有的情况下调用,如果没有呢?当你要去干掉一条龙,意气风发的去跟村长要剑时,发现他竟然没有,当时你就要崩溃,村长一看,“哎哟哟,你可别死我家门口,我问问我老爹有没有”,然后就给该隐打电话,向他借,再不行就让该隐向亚当借,这要是都没有。。以诺就会告诉村民“行了,大家一起死吧,你要的东西大家都没有”。然后全世界就崩溃掉了(野指针:指向了未识别的方法)。
这时候你就要问了,那subclass(meta)又是何方神圣呢?好吧,我也不知道她叫啥,是以诺的媳妇就是了,她藏着以诺的小金库,里边装着村长能用的兵器(类方法),当村长要用时就得向她申请,同理,她没有就得向她妈要,在这里因为女子无需上战场,所以她们本身要兵器。。你猜她们想干嘛,所以她们想要兵器直接向RootClass(meta)夏娃说句悄悄话, 夏娃想要兵器也没地要去,看看自己有啥吧。秉承着男传男,女传女的原则,可以很清楚的看清图中的继承关系。等等,天呐,RootClass(meta)继承于RootClass,这是咋回事?嘿嘿,别忘了,夏娃是用亚当的一根肋骨造出来的。而亚当,你能跟造出他那位打通电话吗?

类与对象的操作函数

Objective-C Runtime 运行时之一:类与对象

上一篇下一篇

猜你喜欢

热点阅读