一界弧、NSArray
NSArray創(chuàng)建的是不可變對象的數(shù)組凿跳,即一旦創(chuàng)建了一個(gè)包含特定數(shù)量的對象的數(shù)組良拼,就不能對數(shù)組進(jìn)行添加呜呐、刪除元素的操作就斤。
為了方便觀察NSArray的內(nèi)存分布,在NSArray對象中存儲(chǔ)同一個(gè)字符串:
NSString *str = @"11";
NSLog(@"字符串常量的地址 %p", str);
NSArray *array = @[str, str, str, str, str];
// 字符串常量的地址 0x108cc2360
str
是字符串常量蘑辑,所以指向的地址是固定的洋机。然后利用x/100xb array
指令觀察array內(nèi)存分布
- 從圖中很明顯發(fā)現(xiàn),第三行到第七行所存儲(chǔ)地址正好就是字符串常量的地址洋魂。
- 根據(jù)OC對象的定義绷旗,前8個(gè)字節(jié)(對應(yīng)第一行內(nèi)容),是
isa
(包含對象信息副砍、引用計(jì)數(shù)衔肢、類指針...)
- 經(jīng)過多次調(diào)試,可以發(fā)現(xiàn)第二行地址存儲(chǔ)的為數(shù)組的長度豁翎。
所以很明顯角骤,NSArray創(chuàng)建時(shí),會(huì)根據(jù)所存儲(chǔ)內(nèi)容申請一片連續(xù)的空間心剥,也由于這種內(nèi)存分配方式邦尊,不方便進(jìn)行內(nèi)存調(diào)整,也符合了不可變數(shù)組的定義优烧。
一蝉揍、NSMutableArray
NSMutableArray 繼承自 NSArray,是一個(gè)可變數(shù)組匙隔,可以對數(shù)組的元素進(jìn)行增刪改查疑苫。
通NSArray一樣熏版,在NSMutableArray對象中存儲(chǔ)同一個(gè)字符串:
NSString *str = @"11";
NSLog(@"字符串常量的地址 %p", str);
NSMutableArray *array = [NSMutableArray arrayWithCapacity:1];
for (int i = 0; i < 10; i ++) {
[array addObject:@"11"];
}
// 字符串常量的地址 0x10043e360
- 和NSArray類似,第一行存儲(chǔ)的依然
isa
- 內(nèi)存中并沒有找到字符串常量的地址捍掺,經(jīng)猜測和調(diào)試驗(yàn)證撼短,數(shù)組中的內(nèi)容單獨(dú)存儲(chǔ)在另外一塊連續(xù)空間中,再將數(shù)組元素首地址存在在數(shù)組中挺勿;
根據(jù)內(nèi)存分布情況曲横,可以通過修改指針直接獲取內(nèi)存中的值,通過下面代碼可分別獲取數(shù)組內(nèi)容首地址的值和數(shù)組容量capacity
的值
@implementation NSArray (address)
- (void *)elementsAddress {
void *address = (__bridge void *)self;
return *((void **)address + 2);
}
- (int)capacity {
void *address = (__bridge void *)self;
return *((int *)address + 7);
}
@end
通過多次調(diào)試不瓶,可發(fā)現(xiàn)禾嫉,數(shù)組擴(kuò)容的規(guī)律,也并不是網(wǎng)上所說的容量不夠時(shí)蚊丐,會(huì)申請一塊雙倍容量的空間熙参。而且通過
arrayWithCapacity
方法創(chuàng)建時(shí),會(huì)提前申請一塊連續(xù)的空間麦备,節(jié)省了很多擴(kuò)容的操作孽椰,但是并不一定和傳遞進(jìn)去的容量一致(例如參數(shù)為100時(shí),實(shí)際容量只有16)凛篙。所以數(shù)組通過這種間接指向的方式黍匾,可以方便的進(jìn)行擴(kuò)容,以及數(shù)據(jù)的修改呛梆。
數(shù)組擴(kuò)容流程:
- 申請一塊新的空間
- 將原數(shù)據(jù)拷貝到新的地址中去
- 釋放原數(shù)據(jù)存儲(chǔ)空間锐涯,并將指針指向新的內(nèi)存區(qū)域
文中用到的
x
指令,是memory read
的縮寫填物,其中b
代表以字節(jié)為單位進(jìn)行打印纹腌,x
代表以16位格式顯示數(shù)據(jù)。x/100xb array
就代表打印array地址開始的100個(gè)字節(jié)的內(nèi)容以16位格式顯示