经过上一章节的学习,咱们已经了解了对象的底层实现,那么类,NSObject在底层是以什么方式存在的呢,属性,方法,协议,都是怎么存在于类里面的,这一章节就来深刻了解一下数组
传送门☞iOS底层探索-准备工做bash
传送门☞iOS底层学习-OC对象前世此生app
建立以下类post
@interface LGPerson : NSObject{
NSString *hobby;
}
@property (nonatomic, copy) NSString *nickName;
- (void)sayHello;
+ (void)sayHappy;
@end
复制代码
@implementation LGPerson
- (void)sayHello{
NSLog(@"LGPerson say : Hello!!!");
}
+ (void)sayHappy{
NSLog(@"LGPerson say : Happy!!!");
}
@end
复制代码
int a = 10;
int b = 10;
LGNSLog(@"%d -- %p",a,&a);
LGNSLog(@"%d -- %p",b,&b);
输出:
KC打印: 10 -- 0x7ffeefbff4fc
KC打印: 10 -- 0x7ffeefbff4f8
复制代码
LGPerson *p1 = [LGPerson alloc];
LGPerson *p2 = [LGPerson alloc];
LGNSLog(@"%@ -- %p",p1,&p1);
LGNSLog(@"%@ -- %p",p2,&p2);
输出:
KC打印: <LGPerson: 0x100544c30> -- 0x7ffeefbff4f8
KC打印: <LGPerson: 0x100545a20> -- 0x7ffeefbff4f0
复制代码
经过以上两个例子,能够得出学习
// 数组指针
int c[4] = {1,2,3,4};
int *d = c;
NSLog(@"%p - %p - %p",&c,&c[0],&c[1]);
NSLog(@"%p - %p - %p",d,d+1,d+2);
for (int i = 0; i<4; i++) {
// int value = c[i];
int value = *(d+i);
LGNSLog(@"%d",value);
}
NSLog(@"指针 - 内存偏移");
复制代码
类的实现实在编译期就申请好内存了,因此咱们须要能够在编译期查看类的底层实现 编译后经过MackOView能够看到,LGPerson类已经生成ui
LGPerson *person = [LGPerson alloc];
Class pClass = object_getClass(person);
复制代码
经过clang命令编译main文件后获得cpp文件,能够发现,Class的底层结构是objc_class
,里面有一个废弃的isa指针,因此不作研究.atom
objc_class
结构以下,是继承自
objc_object
,因此其实类也是一种对象,所谓
万物皆对象
objc_object
定义中,NSObject是OC对objc_object的仿写,结构是同样的
咱们能够看到objc_class
成员变量主要有一下四个spa
Class ISA
:主要关联类Class superclass
:父类cache_t cache
class_data_bits_t bits
cache_t cache
为一个结构体,所占字节数也如图所示,共16字节,不足以存放类中的属性和方法,因此,属性方法等数据,必定存储在
class_data_bits_t bits
结构中
属性方法等数据是存储在class_data_bits_t bits
中,而且能够看到class_rw_t
中的数据都是来自于此。且结构中存在属性,方法,协议列表等,所以遇到跟踪class_data_bits_t bits
,能够经过指针偏移来获取到class_data_bits_t bits
中的数据,经过结构可知,在首地址偏移32字节便可获得3d
咱们能够经过LLDB命令和指针偏移,一步步来探索指针
首先打印出类的16进制存储
0x1000023b0
偏移32字节,在16进制下也就是
0x20
,获得
0x00000001000023d0
,因为
class_data_bits_t bits
不是对象类型,因此须要强转一下,获得以下地址
class_rw_t
结构的data,那么调用方法可获得
class_rw_t
中的内容以下
经过上面打印出的class_rw_t
中,咱们能够看到,根据名称,属性应该是存储在properties
中,经过命令打印可得下图
list_array_tt
结构可得此为二维数组,且根据结构可得数据应该存储在
list
结构中
property_list_t
,可得其继承自
entsize_list_tt
,打印其中的元素
Element first;
能够获得保存的类中保存的属性
在上述探寻属性的过程当中,咱们并无看到成员变量的保存,因此,成员变量不是保存在properties
中,应该是存在其余的结构中,根据class_rw_t
结构思考可得,ro
中存储成员变量的可能性较大,因此按照上述流程探寻ro
const class_ro_t
中存在一个
ivars
,成员变量应该在此
ivars
,发现其中first中已经有了咱们的属性hobby,验证成功
count
咱们发现为2,因此应该还有一个成员变量,咱们能够打印发现是
_nickName
,因此说明
属性会自动生成对应的下划线成员变量
经过对class_rw_t
研究,咱们发现有一个methods
元素,那么这个颇有可能就是存放方法的列表,经过打印咱们可得
list
,能够发现咱们的实例方法
sayHello
,此时已经验证了方法的存储
count
为4,咱们看一下剩下的是什么方法。咱们发现是属性的get和set方法已经默认的析构方法,验证了
属性会自动建立get和set
经过上面的存储探究,咱们发现并无类对象中并无类方法的存储,且类继承子NSObject
,且NSObject
中并无对应的类方法,因此,咱们能够猜想,类方法是存在于元类之中的,经过类对象的isa能够找到元类
经过上面的一系列探索,咱们可得以下结论
objc_object
class_rw_t
结构体中