提前声明:本系列文章的objc源码是基于objc-723源码的。不同的版本,可能都有所不同,但相信除了部分语法及机制上的变更,不会有本质的差别。
关于Objc的运行时原理及消息机制,对于做iOS开发的人,或多或少都有所接触。然而,由于这部分知识在我们的项目中使用的频率实在太低。因此,对于大多数从事iOS开发的人而言是学而不精。即便,我们曾多次回顾这些知识。可能真到某一节点,还是会从头来复习一边,以增进理解。可是,到目前为止,并没有一份很好的资料来体系化的介绍关于Objc的源码。
今天,我们就开始我们这一系列教材的第一篇,读objc.h文件。
为什么,要从这个文件开始呢?很简单,我们平日里做Objc开发时,最基本最直接的就放在这个文件里了。
打开文件,忽略掉引入的头文件和一些非关键信息,我们看到的第一条语句是:
typedef struct objc_class *Class;
这就是我们平日里用到的Class类型了。而紧随其后的是Objc面向对象编程中,实例的结构表示的定义:
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
typedef struct objc_object *id;
id即是我们平日里用的比较多的Objc对象的一个类型表示。
接下来,则是我们常用的SEL:
typedef struct objc_selector *SEL;
之后即是我们平日不常用,也不常见,但对Objc的整个方法调用机制极为重要的IMP了:
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif
紧接着往下,是对BOOL及其对应的值YES与NO的定义和对Nil与nil的定义。在这里要强调一下,从源码的角度来讲,Nil与nil在定义上是完全一样的,两者的用途也没有严格的要求,也就是说,两者本质上是可以通用的,但是,还是建议我们按章通常的约定用Nil表示空类,用nil表示对空象。至于为什么这么说,原因很多,就不细说了。当然,如果你硬要将两者用到混用,其实谁也无法阻止,毕竟最后及其都会将二者识别为相同的东西。
再继续往下,则是对非ARC(或称MRC)机制下的关于引用计数内存管理相关的参数的保护性定义。这包括__strong,__unsafe_unretained,__autoreleasing。
继续往下看,定义的是几个与函数或方法名操作相关的:
OBJC_EXPORT const char * _Nonnull sel_getName(SEL _Nonnull sel) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT SEL _Nonnull sel_registerName(const char * _Nonnull str) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT const char * _Nonnull object_getClassName(id _Nullableobj) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT void* _Nullable object_getIndexedIvars(id _Nullable obj) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0) OBJC_ARC_UNAVAILABLE;
OBJC_EXPORT BOOL sel_isMapped(SEL _Nonnull sel) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
OBJC_EXPORT SEL _Nonnull sel_getUid(const char * _Nonnull str) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
紧接着的几个操作都是针对内存引用技术的操作,在当前版本下已经被废弃。但是,这并不意味着这对我们就不重要了。因为下面的几个操作在比较老的版本中,对内存管理是比较重要的。只是随着objc版本的不断迭代改进,而在当前的版本废弃了而已,不过言归正传,对这几个操作的了解可以帮我们加深对内存管理的理解,但是在实际应用场景中,我们基本上没用直接用过。
typedef const void* objc_objectptr_t;
OBJC_EXPORT id _Nullable objc_retainedObject(objc_objectptr_t _Nullable obj) OBJC_UNAVAILABLE("use CFBridgingRelease() or a (__bridge_transfer id) cast instead");
OBJC_EXPORT id _Nullable objc_unretainedObject(objc_objectptr_t _Nullable obj) OBJC_UNAVAILABLE("use a (__bridge id) cast instead");
OBJC_EXPORT objc_objectptr_t _Nullable objc_unretainedPointer(id _Nullable obj) OBJC_UNAVAILABLE("use a __bridge cast instead");
最后,是基于基本类型声明的几个有意义的别名及对上面部分函数的简化宏定义。到这一步,我们在日常的Objc工作中,常用到的Class,id, SEL, 及IMP都已经展示在了我们面前。同时我们也应该关心一下Nil与nil,尽量不要将二者不加区分混用。这片文章,到此结束。在后续的文章中,我们将以这边文章的内容为点不断地进行扩散。