一、概念
Obj-C是一门动态语言。在编一阶段并不知道变量的具体类型,也不知道具体调用的哪个函数。只有在运行时才检查变量的数据类型,同时在运行时才根据函数名查找要调用的具体函数。
Obj-C把一些决定性的工作从编译、链接阶段推迟到运行时阶段的机制使得Obcj-C更加灵活。
runtime就是Obj-C实现动态化的基础。
二、消息机制的基本原理
1、编译阶段:[receiver selector]; 方法被编译器转换为
- objc_msgSend(receiver,selector) (不带参数)
- objc_msgSend(recevier,selector,org1,org2,…)(带参数)
2、运行时阶段:消息接受者 receiver 寻找对应的 selector。
- 1、通过receiver的 isa 指针找到receiver对应的 class;
- 2、在 class 的 cache 的列表中找到对应的 IMP;
- 3、如果在 cache 中没有找到对应的 IMP,就继续在 class 的 method list中寻找,如果找到就填充到cache中并返回selector;
- 4、如果再class中没有找到这个 selector 就继续在它的 superClass 寻找
- 5、如果找不到 selector ,消息被转发或者临时向 receiver 添加这个 selector对应的实现方法,否则就会崩溃。(后边会详细说下转发)
三、基础概念说明
3.1、class
在 objc/runtime.h 中,class被定义为指向 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;
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;
上边是老的(但应该是常规考察用的比较多),新的实现如下
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
class_rw_t *data() {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
void setInfo(uint32_t set) {
assert(isFuture() || isRealized());
data()->setFlags(set);
}
void clearInfo(uint32_t clear) {
assert(isFuture() || isRealized());
data()->clearFlags(clear);
}
// set and clear must not overlap
void changeInfo(uint32_t set, uint32_t clear) {
assert(isFuture() || isRealized());
assert((set & clear) == 0);
data()->changeFlags(set, clear);
}
bool hasCustomRR() {
return ! bits.hasDefaultRR();
}
void setHasDefaultRR() {
assert(isInitializing());
bits.setHasDefaultRR();
}
void setHasCustomRR(bool inherited = false);
void printCustomRR(bool inherited);
bool hasCustomAWZ() {
return ! bits.hasDefaultAWZ();
}
void setHasDefaultAWZ() {
assert(isInitializing());
bits.setHasDefaultAWZ();
}
void setHasCustomAWZ(bool inherited = false);
void printCustomAWZ(bool inherited);
bool requiresRawIsa() {
return bits.requiresRawIsa();
}
void setRequiresRawIsa(bool inherited = false);
void printRequiresRawIsa(bool inherited);
bool canAllocIndexed() {
assert(!isFuture());
return !requiresRawIsa();
}
bool canAllocFast() {
assert(!isFuture());
return bits.canAllocFast();
}
bool hasCxxCtor() {
// addSubclass() propagates this flag from the superclass.
assert(isRealized());
return bits.hasCxxCtor();
}
void setHasCxxCtor() {
bits.setHasCxxCtor();
}
bool hasCxxDtor() {
// addSubclass() propagates this flag from the superclass.
assert(isRealized());
return bits.hasCxxDtor();
}
void setHasCxxDtor() {
bits.setHasCxxDtor();
}
bool isSwift() {
return bits.isSwift();
}
#if SUPPORT_NONPOINTER_ISA
// Tracked in non-pointer isas; not tracked otherwise
#else
bool instancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
assert(isFuture() || isRealized());
return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS;
}
void setInstancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
assert(isFuture() || isRealized());
setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
}
#endif
bool shouldGrowCache() {
return true;
}
void setShouldGrowCache(bool) {
// fixme good or bad for memory use?
}
bool shouldFinalizeOnMainThread() {
// finishInitializing() propagates this flag from the superclass.
assert(isRealized());
return data()->flags & RW_FINALIZE_ON_MAIN_THREAD;
}
void setShouldFinalizeOnMainThread() {
assert(isRealized());
setInfo(RW_FINALIZE_ON_MAIN_THREAD);
}
bool isInitializing() {
return getMeta()->data()->flags & RW_INITIALIZING;
}
void setInitializing() {
assert(!isMetaClass());
ISA()->setInfo(RW_INITIALIZING);
}
bool isInitialized() {
return getMeta()->data()->flags & RW_INITIALIZED;
}
void setInitialized();
bool isLoadable() {
assert(isRealized());
return true; // any class registered for +load is definitely loadable
}
IMP getLoadMethod();
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isRealized() {
return data()->flags & RW_REALIZED;
}
// Returns true if this is an unrealized future class.
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isFuture() {
return data()->flags & RW_FUTURE;
}
bool isMetaClass() {
assert(this);
assert(isRealized());
return data()->ro->flags & RO_META;
}
// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
bool isRootClass() {
return superclass == nil;
}
bool isRootMetaclass() {
return ISA() == (Class)this;
}
const char *mangledName() {
// fixme can't assert locks here
assert(this);
if (isRealized() || isFuture()) {
return data()->ro->name;
} else {
return ((const class_ro_t *)data())->name;
}
}
const char *demangledName(bool realize = false);
const char *nameForLogging();
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() {
assert(isRealized());
return data()->ro->instanceSize;
}
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
void setInstanceSize(uint32_t newSize) {
assert(isRealized());
if (newSize != data()->ro->instanceSize) {
assert(data()->flags & RW_COPIED_RO);
*const_cast<uint32_t *>(&data()->ro->instanceSize) = newSize;
}
bits.setFastInstanceSize(newSize);
}
};
从中可以看出,在老的写法中 objc_class定义了很多变量:
ivars 自身的所有实例变量
methodLists 方法列表
protocols 协议列表
...
等等。。。 objc_class 结构体 存放的数据称为 元数据(metadata)。
objc_class 结构体 的第一个成员变量是 isa 指针,isa 指针 保存的是所属类的结构体的实例的指针,这里保存的就是 objc_class 结构体的实例指针,而实例换个名字就是 对象。换句话说,Class(类) 的本质其实就是一个对象,我们称之为 类对象。
新的runtime把方法列表,变量放到了 class_rw_t 中
3.2、Object
Object的源码如下
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
id被定义为一个指向objc_object的指针,从源码中可以看到objc_object只包含一个Class类型的isa指针。
当我们对一个对象进行方法调用的时候,他会通过 objc_object 的isa指针去找对应的objc_class,然后在 objc_class中找到对应的方法、实例变量等。
3.3、Meta Class
Meta Class(元类) 就是一个类对象所属的 类。一个对象所属的类叫做 类对象,而一个类对象所属的类就叫做 元类。
Runtime 中把类对象所属类型就叫做 Meta Class(元类),用于描述类对象本身所具有的特征,而在元类的 methodLists 中,保存了类的方法链表,即所谓的「类方法」。并且类对象中的 isa 指针 指向的就是元类。每个类对象有且仅有一个与之相关的元类。
类方法的调用过程 和对象方法调用差不多,流程如下:
- 1、通过类对象 isa 指针 找到所属的 Meta Class(元类);
- 2、在 Meta Class(元类) 的 method list(方法列表) 中找到对应的 selector;
- 3、执行对应的 selector。
3.4、实例对象、类、元类之间的关系
上图就是三者之间的关系。
isa 指针:
- 1、水平方向上,每一级中的 实例对象 的 isa 指针 指向了对应的 类对象,而 类对象 的 isa 指针 指向了对应的 元类。而所有元类的 isa 指针 最终指向了 NSObject 元类,因此 NSObject 元类 也被称为 根元类。
- 2、垂直方向上, 元类 的 isa 指针 和 父类元类 的 isa 指针 都指向了 根元类。而 根元类 的 isa 指针 又指向了自己。
3.5、Method
object_class 结构体 的 methodLists(方法列表)中存放的元素就是 Method(方法)。
源码如下
///这是老的写法,从后边注释可以看到
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
新的写法如下
struct method_t {
SEL name;
const char *types;
IMP imp;
struct SortBySELAddress :
public std::binary_function<const method_t&,
const method_t&, bool>
{
bool operator() (const method_t& lhs,
const method_t& rhs)
{ return lhs.name < rhs.name; }
};
};
结构变化不大,多了个排序的结构体。
可以看到,不管新旧写法,其中都包含了 method_name(方法名),method_types(方法类型) 和 method_imp(方法实现)。
1、SEL method_name; // 方法名
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
SEL是一个指向objc_selector的指针, SEL的内容为存储方法名的字符串
2、IMP method_imp; // 方法实现
/// A pointer to the function of a method implementation.
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id (*IMP)(id, SEL, ...);
#endif
IMP 的实质是一个函数指针,所指向的就是方法的实现。IMP用来找到函数地址,然后执行函数。
3、char *method_types;
方法类型 method_types 是个字符串,用来存储方法的参数类型和返回值类型。