舉例:對(duì)象存儲(chǔ)在堆么鹤,而block存儲(chǔ)在棧凤巨。
創(chuàng)建一個(gè)對(duì)象:
NSObject *obj = [[NSObject alloc] init];
這行代碼創(chuàng)建了一個(gè)obj對(duì)象外遇,指針obj存儲(chǔ)在棧索绪,obj指向的對(duì)象存儲(chǔ)在堆,目前 Objective-C 并不支持直接在棧上創(chuàng)建對(duì)象漠其,但可以通過如下方式間接地創(chuàng)建:
struct {
Class isa;
} fakeNSObject;
fakeNSObject.isa = [NSObject class];
NSObject *obj = (NSObject *)&fakeNSObject;
NSLog(@"%@", [obj description]);
一 . 為什么對(duì)象存在堆里嘴高,而不是存在棧竿音,棧的讀寫速度快且內(nèi)存管理方便,不會(huì)造成內(nèi)存泄漏拴驮,而堆相對(duì)來來說就慢很多春瞬。
原因:
1.Objective-C 變量有效范圍是由 “{}” 包含的塊來決定的,也就是說棧對(duì)象的生命周期僅限于其所在的塊里套啤,出了塊立馬會(huì)被釋放宽气。一個(gè)對(duì)象被創(chuàng)建以后有可能會(huì)通過方法調(diào)用傳遞到別的方法,當(dāng)棧對(duì)象的創(chuàng)建方法返回時(shí)纲岭,棧對(duì)象會(huì)被一起 pop 出棧而釋放抹竹,導(dǎo)致其沒法在別處被繼續(xù)持有线罕。此時(shí) retain 操作會(huì)失效止潮,除非用 copy 方法在想持有該棧對(duì)象的地方重新拷貝一份屬于自己的棧對(duì)象。
因此钞楼,棧對(duì)象回給對(duì)象的內(nèi)存管理造成相當(dāng)大的麻煩喇闸。
2.現(xiàn)代操作系統(tǒng)的棧和線程綁定,而椦空間是有限的燃乍,具體如下:
512 KB (secondary threads)
8 MB (OS X main thread)
1 MB (iOS main thread)
因此對(duì)象如果都在棧上創(chuàng)建不太現(xiàn)實(shí),而堆只要物理內(nèi)存不告警可以無限制使用宛琅。
綜合以上優(yōu)缺點(diǎn)刻蟹,Objective-C 選擇用堆存儲(chǔ)對(duì)象。
二 . 真正的棧對(duì)象block
入行第一年的時(shí)候老人就告訴我們想持有一個(gè) block 要用 copy 將 block 從椇俦伲拷貝到堆上舆瘪。 Objective-C 里的 block 卻是棧對(duì)象,因此棧對(duì)象面臨的問題在 block 身上一個(gè)都不少红伦,但由于 block 是僅有的特殊對(duì)象英古,大家對(duì)它的特殊都已經(jīng)習(xí)慣了,
另外昙读,根據(jù)前面所說召调,棧對(duì)象的有效區(qū)域僅限于其所在的塊,因此像下面的代碼就無法輸出期望的結(jié)果:
void (^block)();
if(x)
{
block = ^{ printf("x\n"); };
}
else
{
block = ^{ printf("not x\n"); };
}
block();
這也是大家需要特別注意的地方蛮浑。