所有观点是本人个人测试与推断,不能完全代表实际。
为方便读者,结论部分已加粗,源码在结尾给出。
笔者经常听别人说NSArray是顺序表结构,或者通过反编译插件打开NSArray的源码。但是笔者本身并不会用相应的插件,所以想用代码的方式探寻一下NSArray的数据结构。
NSArray
本人按照NSArray是顺序表来推测,做了以下工作:
笔者的方法是,根据array的指针,通过C指针位移方法,查找array所有的存储单位,根据所存的内容与log区数组存储对象的地址比对,找到对象在array中的位置。
根据上述思路和代码,可得结果。
由此笔者推断,array确实是顺序表,array第二个存储单元存储的是count,第3-(count+2)个存储单元存储对应对象。且根据不管array建立多少个,他的第一个存储单元恒相同,推断与isa指针有关。
至于总申请空间大小笔者还不知道如何计算。
NSSet
set的数据结构跟Array大差不差,只不过最后一个元素40e8不见了,到了0x0000000282f3c310的位置,由此推测,set应该也是一个顺序表,但他不是顺序表的普通结构,set[2]与set[3]之间隔了两个存储空间,两个存储空间存储均为空应该会在搜索时跳过,但他一定不是一个链表,因为他没有链。
第一个存储空间存放的数据
笔者又做了关于第一个存储空间的测试
发现第一个存储空间的数据笔者没有能力作为地址解析。但是发现所有数组或集合的第一存储空间内容按类相同,于是根据对比isa指针与第一存储内容关系的比较得到以下推论:
第一个存储空间存储得并不是指针,而是按位存储的内容,一共八个字节是64位,前28位为固定值(000021a)可能与版本等固有信息有关,后36位的值减去1得到本类的isa指针。以isa指针来关联方法。
以下给出源码
//初始化一个数组拿到OC指针型
NSArray *array=@[@"1",@"12",@"123",@"1234"];
NSSet*set=[NSSetsetWithArray:array];
//将这个数组指针转换为C指针,这样就可以用C方法进行内存位移访问
char *p=(__bridge_retained void*)array;
//因为OC地址是8个字节,这里推断OC数组也是8个字节作为一个元素存储空间;
intlenght=8;
//进行一次按存储空间的遍历这里预留了四个空间的长度,因为笔者担心OC数组并不是C数组,可能有加料,所以设长一点;
for(inti=0; i<(array.count+4)*lenght; i+=lenght) {
//初始化字符串作为容器来拼接存储内容。
NSMutableString *mString=[NSMutableString string];
//这里要按存储空间的每个字节取值,这里为什么用倒序,因为appending函数是往后拼接,所以高位开始,其实正序从低位拼接也不影响
for(intj=7;j>=0;j--){
//这里十六进制取两位已经足够一字节的数据了,针对数据出现ffffff的情况进行处理
NSString*str=[NSStringstringWithFormat:@"%02x",*(p+i+j)];
str = [strsubstringFromIndex:str.length-2];
[mStringappendFormat:@"%@",str];
}
NSLog(@"数组第%d个单元读到的数据是:%@",i/lenght,mString);
}
ClassarrayClass=object_getClass(array);
NSLog(@"%p,%@",arrayClass,arrayClass);
以上便是笔者的初步结论。后续会更新可变数组与集合。如有错漏,不吝指正。感谢。