所有觀點(diǎn)是本人個人測試與推斷,不能完全代表實際。
為方便讀者,結(jié)論部分已加粗,源碼在結(jié)尾給出。
筆者經(jīng)常聽別人說NSArray是順序表結(jié)構(gòu),或者通過反編譯插件打開NSArray的源碼。但是筆者本身并不會用相應(yīng)的插件,所以想用代碼的方式探尋一下NSArray的數(shù)據(jù)結(jié)構(gòu)。
NSArray
本人按照NSArray是順序表來推測,做了以下工作:
筆者的方法是,根據(jù)array的指針,通過C指針位移方法,查找array所有的存儲單位,根據(jù)所存的內(nèi)容與log區(qū)數(shù)組存儲對象的地址比對,找到對象在array中的位置。
根據(jù)上述思路和代碼,可得結(jié)果。
由此筆者推斷,array確實是順序表,array第二個存儲單元存儲的是count,第3-(count+2)個存儲單元存儲對應(yīng)對象。且根據(jù)不管array建立多少個,他的第一個存儲單元恒相同,推斷與isa指針有關(guān)。
至于總申請空間大小筆者還不知道如何計算。
NSSet
set的數(shù)據(jù)結(jié)構(gòu)跟Array大差不差,只不過最后一個元素40e8不見了,到了0x0000000282f3c310的位置,由此推測,set應(yīng)該也是一個順序表,但他不是順序表的普通結(jié)構(gòu),set[2]與set[3]之間隔了兩個存儲空間,兩個存儲空間存儲均為空應(yīng)該會在搜索時跳過,但他一定不是一個鏈表,因為他沒有鏈。
第一個存儲空間存放的數(shù)據(jù)
筆者又做了關(guān)于第一個存儲空間的測試
發(fā)現(xiàn)第一個存儲空間的數(shù)據(jù)筆者沒有能力作為地址解析。但是發(fā)現(xiàn)所有數(shù)組或集合的第一存儲空間內(nèi)容按類相同,于是根據(jù)對比isa指針與第一存儲內(nèi)容關(guān)系的比較得到以下推論:
第一個存儲空間存儲得并不是指針,而是按位存儲的內(nèi)容,一共八個字節(jié)是64位,前28位為固定值(000021a)可能與版本等固有信息有關(guān),后36位的值減去1得到本類的isa指針。以isa指針來關(guān)聯(lián)方法。
以下給出源碼
//初始化一個數(shù)組拿到OC指針型
? ? NSArray *array=@[@"1",@"12",@"123",@"1234"];
? ? NSSet*set=[NSSetsetWithArray:array];
? ? //將這個數(shù)組指針轉(zhuǎn)換為C指針,這樣就可以用C方法進(jìn)行內(nèi)存位移訪問
? ? char *p=(__bridge_retained void*)array;
? ? //因為OC地址是8個字節(jié),這里推斷OC數(shù)組也是8個字節(jié)作為一個元素存儲空間;
? ? intlenght=8;
? ? //進(jìn)行一次按存儲空間的遍歷這里預(yù)留了四個空間的長度,因為筆者擔(dān)心OC數(shù)組并不是C數(shù)組,可能有加料,所以設(shè)長一點(diǎn);
? ? for(inti=0; i<(array.count+4)*lenght; i+=lenght) {
? ? ? ? //初始化字符串作為容器來拼接存儲內(nèi)容。
? ? ? ? NSMutableString *mString=[NSMutableString string];
? ? ? ? //這里要按存儲空間的每個字節(jié)取值,這里為什么用倒序,因為appending函數(shù)是往后拼接,所以高位開始,其實正序從低位拼接也不影響
? ? ? ? for(intj=7;j>=0;j--){
? ? ? ? ? ? //這里十六進(jìn)制取兩位已經(jīng)足夠一字節(jié)的數(shù)據(jù)了,針對數(shù)據(jù)出現(xiàn)ffffff的情況進(jìn)行處理
? ? ? ? ? ? NSString*str=[NSStringstringWithFormat:@"%02x",*(p+i+j)];
? ? ? ? ? ? str = [strsubstringFromIndex:str.length-2];
? ? ? ? ? ? [mStringappendFormat:@"%@",str];
? ? ? ? }
? ? ? ? NSLog(@"數(shù)組第%d個單元讀到的數(shù)據(jù)是:%@",i/lenght,mString);
? ? }
? ? ClassarrayClass=object_getClass(array);
? ? NSLog(@"%p,%@",arrayClass,arrayClass);
以上便是筆者的初步結(jié)論。后續(xù)會更新可變數(shù)組與集合。如有錯漏,不吝指正。感謝。