筆者最近看到兩道iOS筆試題目,當時就呆住了。ios
int a[5] = {1, 2, 3, 4, 5};
int *ptr = (int *)(&a + 1);
NSLog(@"a的地址 : %p", a);
NSLog(@"a + 4 的地址: %p", a + 4);
NSLog(@"ptr - 1 的地址 : %p", ptr - 1);
NSLog(@"a + 1 的值 : %d", *(a + 1));
NSLog(@"p - 1 的值 : %d", *(ptr - 1));
複製代碼
在C語言中,a和a[0]指向同一個地址。因此不難理解 a[1]的地址比a[0](即a)大了4。算法
聲明瞭a[5],存儲類型爲int。因此數組a的大小也肯定了,爲(5 * 4)。因此假設a地址爲0,ptr的地址是21。因爲p指針指向類型爲int,因此(p - 1)理所固然也指向a[4]。數組
對於動態數組,則須要藉助數據結構來實現。bash
因而筆者對iOS集合怎麼存儲提起了興趣。數據結構
測試一遍,發現結果爲23。感慨一句,NSSet到底是怎麼存儲的。測試
開始前,先提一句,集合中不能存儲基本數據類型,將保持與元素對象的強引用關係。spa
NSArray : A static ordered collection of objects. NSMutableArray : A dynamic ordered collection of objects..net
和C不同,OC是門面向對象的語言。*array,固然指向數組對象的地址,而不是array[0]。換句話說,array和array[0]並不指向同一地方。那麼array[0]、array[1]、array[2]是怎麼找到該對象的,或者說怎麼存儲的呢?3d
因而筆者打下如下代碼,發現取不到array[0]返回的指針地址。也想不出來怎麼取。 指針
因而查閱到兩篇大牛寫的文章,CFArray 的歷史淵源及實現原理和NSMutableArray原理揭露
在修改元素的操做中,CFArray 也略顯得暴力一些,先對數組進行大塊的分區操做,再按照順序填充數據,組合成爲一塊新的雙端隊列
簡單地說(筆者看得不怎麼懂,若是有誤,歡迎指出),數組的數據結構是雙端隊列,_size表示數組空間,_used表示多少個元素,_offset表示a[0]的偏移量。因此中間位置的操做會慢於兩端。
如圖,相似緩衝區嵌套 map 表。
當不夠容量時,擴容,修改_size,在緩衝區中標記下一塊內容頭地址在哪。有趣的是,_size只能增大,不會縮小。
Set 和 Array的區別在於Set無序且沒有重複元素。
先來看Set是怎麼判斷重複元素的。
Set對元素是否重複的判斷在於兩個方法,- (NSUInteger)hash
和- (BOOL)isEqual:(id)object
。iOS開發 之 不要告訴我你真的懂isEqual與hash!
在《Effective Objective-C 2.0》第8條:理解「對象等同性」提到:
根據等同性約定:若兩對象相等,則其哈希碼(hash)也相等,可是兩個哈希碼相同的對象卻未必相等。
若是沒有重寫這兩個方法,默認只比較指針值是否相等。
因此上面的筆試題中,Person沒有重寫這兩個方法。指針person2指向person1,因此被加到NSSet時,被當成同一個元素。而且person2.age修改成2,person1.age同理。因此最終輸出應該是23。
那麼Set存儲結構是怎麼樣的呢?
從上面咱們能夠看出,Set採用哈希表存儲,運用散列算法。因此元素在內存中是不連續的。
NSDictionary :A static collection of objects associated with unique keys. NSMutableDictionary: A dynamic collection of objects associated with unique keys.
又是一篇筆者看不怎麼懂的文章NSDictionary 內部結構、實現原理。
NSDictionary的結構是鏈地址哈希表。