一愕鼓、NSArray
iOS 在創(chuàng)建 NSArray
時坎弯,一般創(chuàng)建的是 __NSArrayI
對象桂肌,但當(dāng)其只包含一個元素時狰闪,創(chuàng)建的是 __NSSingleObjectArrayI
對象宪肖,沒有任何對象時表制,創(chuàng)建的是 __NSArray0
對象,__NSArrayI
控乾,__NSSingleObjectArrayI
和 __NSArray0
都繼承自 NSArray
么介。
1.__NSSingleObjectArrayI
__NSSingleObjectArrayI
的結(jié)構(gòu)定義為:
@interface __NSSingleObjectArrayI : NSArray
{
id object;
}
@end
__NSSingleObjectArrayI
類內(nèi)部結(jié)構(gòu)簡單,只增加了一個存儲對象的屬性蜕衡。
2.__NSArrayI
@interface __NSArrayI : NSArray
{
NSUInteger _used;
id _list[0];
}
@end
_used
是數(shù)組元素個數(shù)壤短,調(diào)用 [array count]
返回的就是 _used
的值。
id _list[0]
是 C 語言里面的柔性數(shù)組慨仿,不占用內(nèi)存久脯,且相對指針效率更高。
二镰吆、NSMutableArray
iOS 創(chuàng)建 NSMutableArray
時帘撰,實際得到的是其子類 __NSArrayM
對象。__NSArrayM
的結(jié)構(gòu)定義為
@interface __NSArrayM : NSMutableArray
{
NSUInteger _used;
NSUInteger _offset;
int _size:28;
int _unused:4;
uint32_t _mutations;
id *_list;
}
@end
_list
是存儲對象數(shù)組的一塊連續(xù)的內(nèi)存區(qū)域
_used
是數(shù)組元素個數(shù)
_offset
起始偏移量
_size
能存儲的的對象個數(shù)鼎姊,_list
大小骡和。(大于或等于_used
)
_mutations
修改標(biāo)記,每次對 __NSArrayM
的修改操作都會使 _mutations
加1,“*** Collection <__NSArrayM: 0x1002076b0> was mutated while being enumerated.”這個異常就是通過對 _mutations
的識別來引發(fā)的相寇。
分析:__NSArrayM
并沒有使用鏈表結(jié)果存儲內(nèi)存慰于,鏈表雖然在增刪方面有不需要移動數(shù)據(jù)的有優(yōu)勢,但是查找唤衫,分配婆赠,占用空間方面效率低下。在查找方面,數(shù)組可通過內(nèi)存地址偏移迅速找到需要的對象休里,另一方面蛆挫,因為內(nèi)存連續(xù),而且每個數(shù)組元素都只是一個指針妙黍,所以拷貝起來也很快悴侵。
__NSArrayM
用了環(huán)形緩沖區(qū) (circular buffer)。這個數(shù)據(jù)結(jié)構(gòu)相當(dāng)簡單拭嫁,只是比常規(guī)數(shù)組或緩沖區(qū)復(fù)雜點可免。環(huán)形緩沖區(qū)的內(nèi)容能在到達(dá)任意一端時繞向另一端。除非緩沖區(qū)滿了做粤,否則在任意一端插入或刪除均不會要求移動任何內(nèi)存浇借。任意一端插入或者刪除,只是修改 offset
參數(shù)怕品,不需要移動內(nèi)存妇垢,我們訪問的時候只是不和普通的數(shù)組一樣 index
多少就是多少,這里會計算加上 offset
之后處理的值取數(shù)據(jù)肉康, 而不是插入頭和尾巴的時候闯估,環(huán)形結(jié)構(gòu)會根據(jù)最少移動內(nèi)存指針的方式插入
例子:
_offset = 0
_used = 5
_size=6
(1)在末端追加3個對象后:
_offset = 0
_used = 8
_size=8
(2)刪除對象A:
_offset = 1
_used = 7
_size=8
(3)刪除對象E:
_offset = 2
_used = 6
_size=8
(4)在末端追加兩個對象:
_list
足夠存儲新加入的兩個對象,因此沒有重新分配迎罗,而是將兩個新對象存儲到了 _list
起始端_offset = 2
_used = 8
_size=8
擴(kuò)容:當(dāng) __NSArrayM
存儲容量不足時睬愤,會重新 malloc
一塊新的存儲區(qū)域,并將數(shù)據(jù)復(fù)制到新的區(qū)域纹安,最后釋放舊的存儲空間尤辱。
arrayWithCapacity:
方法可以指定 __NSArrayM
的初始容量,也就是 _size
環(huán)形緩沖區(qū)的初始大小厢岂。