内容简介:本文的所涉及到的源码是我们在学习面向对象的学习中,接触最多的就是类,那么在OC类是由Class类型来表示的,Class是用C的数据结构来表示的。可以看到:
本文的所涉及到的源码是 objc4 源码,截止到写本文最新的是 objc4-750 这个版本。
Class
我们在学习面向对象的学习中,接触最多的就是类,那么在OC类是由Class类型来表示的,Class是用C的数据结构来表示的。
看一下 NSObject 的声明,在头文件中,如下图所示:
@interface NSObject<NSObject>{
#pragma clang diagnostic push
#pragma clang diagnostic ignored"-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
可以看到:
1、 NSObject 是实现了 <NSObject> 协议的。
2、 NSObject 中有 Class 类型的 isa 成员变量,外界是无法访问的,另外 isa 指针可能在将来也会被隐藏起来(OBJC_ISA_AVAILABILITY标示了)。
继续看一下 Class 到底是什么?
在上面的文件中可以看到 Class 的定义,如下代码:
typedef struct objc_class *Class; typedef struct objc_object *id;
可以看出 Class 是一个指向 objc_class 的结构体指针, Objective-C 中的类是由 Class 类型来表示的,它实际上是一个指向 objc_class 结构体的指针。
在下面的头文件中看一下 objc_class 的定义,如下:
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
// ....
}
可以看出, objc_class 用来描述OC中的类,而 objc_object 用来描述OC中的对象,类(objc_class)其实也是一个对象(objc_object),另外 id 是代表对象的,它是指向 objc_object 的结构体指针,它的存在可以让我们实现类似于C++中泛型的一些操作。该类型的对象可以转换为任何一种对象,有点类似于 C语言 中 void * 指针类型的作用。
这里要注意, objc_class 的定义在 objc-runtime-old.h 中和 objc-runtime-new.h 中的不一样。这里以 objc-runtime-new.h 为主,建议可以看看被误解的 objc_class 这篇文章。
再来看一下 objc_object ,如下图所示:
struct objc_object {
private:
isa_t isa;
// ...
}
objc_object 是一个结构体,里面有个私有成员变量 isa 是 isa_t 类型的。
而 isa_t 是一个 union 类型的,如下代码:
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
总之在OC中,类也是一个对象称之为类对象,根据凡是对象都有自己的类的原理,那么类对象的肯定存在自己的类,这个类就是元类(meta class)。
元类
在说元类之前,先看一下下面的例子,创建一个 NSMutableDictionary 实例对象 dict ,即向 NSMutableDictionary 发送 alloc 和 init 消息。
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; ``` 上面代码的大概执行流程如下几个步骤: 1、先执行 `[NSMutableDictionary alloc]`,但是 `NSMutableDictionary` 没有 `+alloc` 方法,于是再去父类`NSObject` 中查找该方法。 2、`NSObject` 响应 `+alloc` 方法,开始检测 `NSMutableDictionary` 类,并根据其所需的内存空间大小开始分配内存空间,然后把 `isa` 指针指向 `NSMutableDictionary` 类。同时,`+alloc` 也被加进 cache 列表里面。 3、接着,执行 `-init` 方法,如果 `NSMutableDictionary` 响应该方法,则直接将其加入 `cache`,如果不响应,则去父类查找。 4、在后期的操作中,如果再以 `[[NSMutableDictionary alloc] init]` 这种方式来创建字典对象,则会直接从 cache 中取出相应的方法,直接调用。 上面是创建一个实例对象的大致流程,接下来我们说说元类。 元类简单来说就是类对象的类。类描述的是对象,那么元类描述的就是Class类对象的类。元类定义了类的行为(类方法),在平时开发时,meta class 基本是用不着接触的,但是我们还是要知道它的存在。 ```objc NSMutableDictionary *tDatas = [NSMutableDictionary dictionaryWithCapacity:5];
拿上面的示例来说,向 NSMutableDictionary 发送 dictionaryWithCapacity 这个消息的时候,Runtime 会在这个类的 meta-class 的方法列表中查找,通过 SEL 找到后取出方法中的 IMP 函数入口指针,并执行该方法,如果找不到就进行消息转发的流程中,最终可能会导致 Crash,消息转发的原理和机制可以参考消息机制 这几篇文章。
元类保存了类方法的列表。当一个类方法被调用时,元类会首先查找它本身是否有该类方法的实现,如果没有则该元类会向它的父类查找该方法,直到一直找到继承链的头。
Class object_getClass(id obj);
object_getClass 可以获取一个对象的 class object,其源码实现如下:
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
举个例子吧,示例如下:
NSObject *obj = [NSObject new];
Class obj1 = object_getClass(obj);
Class obj2 = object_getClass([NSObject class]);
Class obj3 = objc_getMetaClass("NSObject");
Class obj4 = object_getClass(obj1);
const char *name = [NSStringFromClass(obj1) UTF8String];
NSLog(@"name: %s", name); //name: NSObject
Class obj5 = objc_getMetaClass(name);
Class obj6 = objc_getClass(name);
NSLog(@"obj : %@, ->%p: ", obj, obj);
NSLog(@"obj1: %@, ->%p: ", obj1, obj1);
NSLog(@"obj2: %@, ->%p: ", obj2, obj2);
NSLog(@"obj3: %@, ->%p: ", obj3, obj3);
NSLog(@"obj4: %@, ->%p: ", obj4, obj4);
NSLog(@"obj5: %@, ->%p: ", obj5, obj5);
NSLog(@"obj6: %@, ->%p: ", obj6, obj6);
打印结果如下:
obj : <NSObject: 0x600002b19d70>, ->0x600002b19d70: obj1: NSObject, ->0x10c96bf38: obj2: NSObject, ->0x10c96bee8: obj3: NSObject, ->0x10c96bee8: obj4: NSObject, ->0x10c96bee8: obj5: NSObject, ->0x10c96bee8: obj6: NSObject, ->0x10c96bf38:
可以看出,obj 是一个实例对象,obj1和obj6是一个 class object,其二者地址也一致,obj2、obj3 和 obj4 都获取到的是元类。
通过类对象调用的 object_getClass 得到的是该类对象的 meta class,如 obj2 和 obj4,而通过实例对象调用的 object_getClass 得到的是该实例对象的类对象,如 obj1, objc_getClass 这个方法获取是实例对象的类对象,与 object_getClass 还是有点不一样的。而 objc_getMetaClass 可以直接获取 meta class,如 obj3。
在 NSObject.mm 中,可以看到 self 和 class 方法都要实例和类方法,class 方法返回的都是类对象。
+ (id)self
{
return (id)self;
}
- (id)self
{
return self;
}
+ (Class)class
{
return self;
}
- (Class)class
{
return object_getClass(self);
}
所以,无论是类还是实例调用 class 方法,返回的都是同一个 class object,举例:
Class objClz1 = [NSObject class];
Class objClz2 = [[[NSObject alloc] init] class];
if (objClz1 == objClz2) {
NSLog(@"objClz1: %@, ->%p", objClz1, objClz1);
}
输出结果是:
objClz1: NSObject, ->0x10fa30f38
isa
下面的例子来源自 这里 ,感谢 kingizz’s blog,下面的代码 Son 是 Father 的子类,而 Father 是 NSObject 的子类。
@interface Father:NSObject @end
@interface Son:Father @end
我们结合下面这个图来理解一下,子类、父类、元类以及 isa 指针。
一个实例对象的 isa 指向对象所属的类,这个类的 isa 指向这个类的元类,而这个元类的 isa 又指向 NSObject 的元类, NSObject 的元类的 isa 指向其本身,最终形成形成一个完美的闭环。
在OC中,所有的对象都有一个 isa 指针,指向对象所属的类,类也是一个对象,类对象的 isa 指针指向类的元类。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
数据结构、算法与应用
(美)Sartaj Sahni / 汪诗林、孙晓东、等 / 机械工业出版社 / 2000-01 / 49.00
本书是关于计算机科学与工程领域的基础性研究科目之一――数据结构与算法的专著。 本书在简要回顾了基本的C++ 程序设计概念的基础上,全面系统地介绍了队列、堆栈、树、图等基本数据结构,以及贪婪算法、分而治之算法、分枝定界算法等多种算法设计方法,为数据结构与算法的继续学习和研究奠定了一个坚实的基础。更为可贵的是,本书不仅仅介绍了理论知识,还提供了50多个应用实例及600多道练习题。 本书......一起来看看 《数据结构、算法与应用》 这本书的介绍吧!