Objective-C的本质
我们平时编写的Objective-C代码,底层实现其实都是C\C++代码,所以Objective-C的面向对象都是基于C\C++的数据结构实现的。
如何将Objective-C代码转换为C\C++代码?
//如果需要链接其他框架,使用-framework参数。比如-framework UIKit
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件
OC对象的本质
NSObject的底层实现
为了方便理解所以直接写Class类,其实是个结构体:
struct NSObject_IMPL NSObject_IVARS
如何实时查看内存数据
Debug -> Debug Workfllow -> View Memory (Shift + Command + M)OC对象的分类
1、instance对象(实例对象)
instance对象就是通过类alloc出来的对象,每次调用alloc都会产生新的instance对象。
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
object1、object2是NSObject的instance对象(实例对象),它们是不同的两个对象,分别占据着两块不同的内存。
instance对象在内存中存储的信息包括:isa指针和其他成员变量。
2、class对象(类对象)
NSObject *object1 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = object_getClass(object1); //Runtime API
objectClass1和objectClass2都是NSObject的class对象(类对象),每个类在内存中有且只有一个class对象。
class对象在内存中存储的信息主要包括:isa指针、superclass指针、类的属性信息(@property)、类的对象方法信息(instance method)、类的协议信息(protocol)、类的成员变量信息(ivar)
3、meta-class对象(元类对象)
Class objectMetaClass = object_getClass([NSObject class]); //Runtime API
objectMetaClass是NSObject的meta-class对象(元类对象),每个类在内存中有且只有一个meta-class对象。
class对象在内存中存储的信息主要包括:isa指针、superclass指针、类的类方法信息(class method)
isa、superclass总结
1、instance的isa指向class
2、class的isa指向meta-class
3、meta-class的isa指向基类的meta-class
4、class的superclass指向父类的class,如果没有父类,superclass指针为nil
5、meta-class的superclass指向父类的meta-class,基类的meta-class的superclass指向基类的class
6、instance调用对象方法的轨迹:isa找到class,方法不存在,就通过superclass找父类
7、class调用类方法的轨迹:isa找meta-class,方法不存在,就通过superclass找父类
窥探struct objc_class的结构
class、meta-class对象的本质结构都是struct objc_class
class_rw_t
class_rw_t里面的methods、properties、protocols是二维数组,是可读可写的,包含了类的初始内容、分类的内容。
class_ro_t
class_ro_t里面的baseMethodList、baseProtocols、ivars、baseProperties是一维数组,是只读的,包含了类的初始内容。
method_t
method_t是对方法\函数的封装。
IMP代表函数的具体实现。
SEL代表方法\函数名,一般叫做选择器,底层结构跟char *类似。
可以通过@selector()和sel_registerName()获得。
可以通过sel_getName()和NSStringFromSelector()转成字符串。
不同类中相同名字的方法,所对应的方法选择器是相同的。
types包含了函数返回值、参数编码的字符。
方法缓存
Class内部结构中有个方法缓存(cache_t),用散列表(哈希表)来缓存曾经调用过的方法,可以提高方法的查找速度。