runtime中数据的结构
高级语言所编写的代码若想被机器识别,首先得翻译成汇编语言,然后再由汇编语言翻译成计算机所能识别的机器语言。高级语言有很多如:java、c++、python及Objective-C等语言,高级语言语法差别很大,但是越往底层翻译越趋向统一。
Objective-C语言是C语言的拓展,使C语言能够面向对象开发。Objective-C语言在编译时不能直接翻译成汇编语言,而是先要翻译成C语言,然后再由C语言进行汇编工作。当Objective-c代码在编译的时候,runtime系统将Objective-c代码翻译成C代码。
下面开始研究当Objective-C到C时,Objective-C中我们经常使用的实例对象、类对象、元类对象、属性及方法等它们的数据结构是怎样的以便我们能深入的了解底层都干了什么。了解底层数据结构,我们能够更好的使用runtimeAPI带来便利及启发我们在开发时的一些思想。
为了学习runtime底层,我们需要下载苹果源码objc4-750,本文围绕苹果objc4-750源码展开。源码获取方式:1.苹果开源源码 2.githup搜索
实例对象
@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
Class isa OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}
Objectivie-C实例对象大多都是继承于NSObject类的子类对象,从以上源码中可以看到有一个isa
指针它的类型是Class
。isa
指针指向这个实例对象的类对象,Class
类型的数据结构是typedef struct objc_class *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
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);
}
从上边源码可以看到类对象源码的大致信息。
-
isa
指针为隐藏指针,指向的是该类的元类对象。 -
superclass
指向的也是一个Class类型,指向的是该类的父类。 -
cache
是类对象的方法缓存列表,缓存类的实例方法。 -
bits
存储类里边的很多数据。如bits
里的datade数据类型class_rw_t
。 -
data
存储的数据类型class_rw_t
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
method_list_t *baseMethods() const {
return baseMethodList;
}
};
class_ro_t
和class_rw_t
的比较:
- 从字面来看
class_ro_t
中ro是readnoly的意思,只能读取不能修改。class_rw_t
中rw是readwirte的意思,可以读写操作。 - class_ro_t结构体存储了类在编译期间确定的属性、方法、协议以及变量。编译期完成之后,将属性,方法及协议存储在ro里边。
- 可以往类结构中增加一些额外的方法、协议,比如在Category中写的方法,Category中的方法就是在运行时加入到类结构中的。运行时生成的类的方法、属性、协议保存在class_rw_t结构体中。
-
const ivar_list_t * ivars
从这里我们可以看到ivars是一个const修饰的,所以在运行时不能给类动态的添加实例变量的。
方法
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; }
};
};
-
SEL name
方法编号,与imp函数指针一一对应。 -
types
方法签名,每个方法都需要方法签名。 -
imp
函数具体实现的指针。
属性
struct property_t {
const char *name;
const char *attributes;
};
-
name
指的是属性的名称 -
attributes
为属性的信息,比如类型和修饰信息。
协议
struct protocol_t : objc_object {
const char *mangledName;
struct protocol_list_t *protocols;
method_list_t *instanceMethods;
method_list_t *classMethods;
method_list_t *optionalInstanceMethods;
method_list_t *optionalClassMethods;
property_list_t *instanceProperties;
uint32_t size; // sizeof(protocol_t)
uint32_t flags;
// Fields below this point are not always present on disk.
const char **_extendedMethodTypes;
const char *_demangledName;
property_list_t *_classProperties;
const char *demangledName();
const char *nameForLogging() {
return demangledName();
}
bool isFixedUp() const;
void setFixedUp();
# define HAS_FIELD(f) (size >= offsetof(protocol_t, f) + sizeof(f))
bool hasExtendedMethodTypesField() const {
return HAS_FIELD(_extendedMethodTypes);
}
bool hasDemangledNameField() const {
return HAS_FIELD(_demangledName);
}
bool hasClassPropertiesField() const {
return HAS_FIELD(_classProperties);
}
# undef HAS_FIELD
const char **extendedMethodTypes() const {
return hasExtendedMethodTypesField() _extendedMethodTypes : nil;
}
property_list_t *classProperties() const {
return hasClassPropertiesField() _classProperties : nil;
}
};
- instanceMethods 必须实现的实例方法
- classMethods 必须实现的类方法
- optionalInstanceMethods 可选的实例方法
- optionalClassMethods 可选的类方法