Objective-C Runtime简介
OC是一种动态类型语言
不知道其他初学Objective-C的童鞋是不是也和我一样,对oc里面的函数调用感到有些陌生,首先它不像c语言或者c++或者java这些语言,将函数调用统称为“调函数”或者“调方法”,而是称之为“发消息”,其次,在oc中“调用”一些根本没有实现的方法时,它甚至也是可以通过编译的。
这两个问题的根源在于OC是一门动态类型的语言,动态与静态分别意味着对象的方法实现是在运行时和编译时决定。实际上面向对象语言的鼻祖Smalltalk就是一门动态类型的语言,而现代的主流编程语言如java,c++等都是静态类型。
而我们经常提到的runtime直接翻译出来就是“运行时”,而OC中的runtime特指runtime library,即一个包含了若干API的库,在官方的说明中是这样介绍runtime的:
You typically don't need to use the Objective-C runtime library directly when programming in Objective-C.
This API is useful primarily for developing bridge layers between Objective-C and other languages, or for low-level debugging.
简意为一般人在用OC开发时并不需要用到runtime库,这个API主要是用于做OC与其他语言桥接开发,亦或是底层调试。
如何获取runtime的源代码
https://opensource.apple.com/source/objc4/
苹果将objc相关的代码在这里面开源,可以在里面找一个较新的版本下载阅读。
Objective-C是基于C的语言,Objective-C中各种对象在底层都有相应的C的实现。
实例/类/对象
实例/类/对象分别是instance/class/object,很多人容易混淆实例与对象的含义,实际上在面向对象的概念里万物皆对象,因此对象是OC中的一个基本数据结构,实例属于一种对象,类也是一种对象。
首先打开objc.h。
找到关于objc_object的声明部分。
/// 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
上面提到,Class是objc_class的一个别名,代表oc下的类对象。
objc_class我们稍后会了解,这里先看objc_object。
objc_object代表一个类的实例对象。它的结构非常简单,只有一个名为isa的成员,它代表一个指向其类对象的指针。(Stack Overflow上有人将isa这种命名解释为 “is a”,有一点道理,因为它代表了对象的类型)
而id代表指向oc对象的指针。
打开runtime.h很快能在前面找到struct objc_class,这即是OC的对象在C中的实现,实际上是一个结构体,来看看其中比较关键的成员。
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
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;
/* Use `Class` instead of `struct objc_class *` */
第一个成员即为isa指针,类对象的isa指针指向其元类(meta class)对象。
super_class,指向其父类对象的指针。
objc_ivar_list代表实例成员列表, ivar(instance variable)指实例变量。
objc_method_list代表方法列表。
objc_cache代表方法缓存。
objc_protocol_list代表协议列表。
方法
Method
method是我们很熟悉的函数概念,在oc中是一个名为objc_method的结构体。
/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method;
struct objc_method {
SEL _Nonnull method_name OBJC2_UNAVAILABLE;
char * _Nullable method_types OBJC2_UNAVAILABLE;
IMP _Nonnull method_imp OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
值得注意的是SEL和IMP,我们在以target action形式设置回调时通常会要求我们传一个SEL类型的数据作为触发方法。
[view addTarget:self action:@selector(touchAction) forControlEvents:UIControlEventTouchUpInside];
就像这样,在@selector()中传入方法名即可得到一个SEL,那么SEL究竟是什么?根据官方文档的说明:
Defines an opaque type that represents a method selector.
typedef struct objc_selector *SEL;
它是一个objc_selector的封装,因此我们无法得知selector的内部实现,目前广泛认为SEL实际上是一个已经注册过的方法名的字符串,因为通过nslog对@selector打印出来的内容就是一个字符串。
下面是SEL的注册过程,即@selector()背后做的事情:
static SEL __sel_registerName(const char *name, bool shouldLock, bool copy)
{
SEL result = 0;
if (shouldLock) selLock.assertUnlocked();
else selLock.assertLocked();
if (!name) return (SEL)0;
result = search_builtins(name);
if (result) return result;
conditional_mutex_locker_t lock(selLock, shouldLock);
auto it = namedSelectors.get().insert(name);
if (it.second) {
// No match. Insert.
*it.first = (const char *)sel_alloc(name, copy);
}
return (SEL)*it.first;
}
static SEL search_builtins(const char *name)
{
#if SUPPORT_PREOPT
if (builtins) {
SEL result = 0;
if ((result = (SEL)builtins->get(name)))
return result;
if ((result = (SEL)_dyld_get_objc_selector(name)))
return result;
} else if (useDyldSelectorLookup) {
if (SEL result = (SEL)_dyld_get_objc_selector(name))
return result;
}
#endif
return nil;
}