簡要概述
iOS創建對象的兩種方式:
①UIView *myView = [[UIView alloc] init];
UIView *myView = [UIView new];
① [[ObjectName alloc] init]
② [ObjectName new]
第一種方式來創建對象時, 系統首先會給變量分配內存,然后調用init方法來進行初始化, 或者調用initWith方法來初始化;
第二種方式是第一種方式的兩步的概括, 系統會直接開辟好內存, 調用init方法來初始化對象,但是只能調用init方法;
具體的區別:
1.alloc在分配內存的時候使用了zone, 它是在給對象分配內存的時候把關聯的對象分配到一個相鄰的區域內, 以便于調用時消耗很少的內存, 提升程序的處理速度;
2.使用new來創建對象的話, 初始化方法被固定死了, 只能使用init, 不能調用其他的initWith方法;
3.使用alloc init方法, 我們可以重寫init方法, 但是如果使用new來創建的話就只能走系統的init方法了.
詳細講解 一
對于NSObject對象來說new的作用是為對象分配內存空間并使用init方法完成初始化,而與alloc&init這種顯式寫法來說不同的是,在分配內存空間的時候alloc相比于new來說會使用default_zone,從開放的objc運行時源碼中的舊Object對象一窺NSObject的new實現
NSZone原本是用于維護一塊用于對象內存分配及釋放的內存池的描述信息,進程默認的NSZone是在啟動的時候創建并將隨后所有的對象均分配在這里,也因此在做了大量的分配及釋放對象內存之后,可能會產生很多的內存碎片,在做新的內存分配的時候NSZone會試圖去填補這些碎片,即從碎片中找到合適的內存區塊以存放新的對象,這個查找的過程是需要時間開銷的。
所以如果需要在短時間內分配大量對象,則可以創建自己的NSZone,那么在分配對象內存的時候,只需要要當前zone的末尾分配即可,相比于去已經臃腫的default zone去分配這批對象,其耗時是更少的
但斯時已逝,像上面的Managing Zones的描述所說的,iOS及osx 64位運行時已經不支持自定義的zone了
好壞已無傷大雅
所以new與alloc&init的區別只剩下是顯示調用還是隱式調用init的問題了,至于那個class_getVersion()是獲取class的version這個其實可以自定義,一般自定義的class的version為0,但自定義的class,就算重載init其version也還是0,調用new的時候直接會進入init。其實這份object.mm已經是GNUC的遺留文件了,在objc體系中并未用到了,可以看到其已經通過ifdef ?!__OBJC2__這一步而將其定義抹去了
詳細講解 二
在實際開發中很少會用到new,一般創建對象咱們看到的全是[[className alloc] init],但是并不意味著你不會接觸到new,在一些代碼中還是會看到[className new],那么,他們兩者之間到底有什么區別呢?我們看源碼:
+new
{
id?newObject?=?(*_alloc)((Class)self,?0);
Class?metaClass?=?self->isa;
if(class_getVersion(metaClass)?>?1)
return[newObject?init];
else
returnnewObject;
}
//而?alloc init?像這樣:
+?alloc
{
return(*_zoneAlloc)((Class)self,?0,?malloc_default_zone());
}
- init
{
returnself;
通過源碼中我們發現,[className new]基本等同于[[className alloc] init];
區別只在于alloc分配內存的時候使用了zone.
這個zone是個什么東東呢?
它是給對象分配內存的時候,把關聯的對象分配到一個相鄰的內存區域內,以便于調用時消耗很少的代價,提升了程序處理速度;
而為什么不推薦使用new?
不知大家發現了沒有:如果使用new的話,初始化方法被固定死只能調用init.
而你想調用initXXX怎么辦?沒門兒!據說最初的設計是完全借鑒Smalltalk語法來的。
傳說那個時候已經有allocFromZone:這個方法,
但是這個方法需要傳個參數id myCompanion = [[TheClass allocFromZone:[self zone]] init];
這個方法像下面這樣:
+ allocFromZone:(void *) z
{
return (*_zoneAlloc)((Class)self, 0, z);
}
//后來簡化為下面這個:
+ alloc
{
return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());
}
但是,出現個問題:這個方法只是給對象分配了內存,并沒有初始化實例變量。
是不是又回到new那樣的處理方式:在方法內部隱式調用init方法呢?
后來發現“顯示調用總比隱式調用要好”,所以后來就把兩個方法分開了。
概括來說,new和alloc/init在功能上幾乎是一致的,分配內存并完成初始化。
差別在于,采用new的方式只能采用默認的init方法完成初始化,
采用alloc的方式可以用其他定制的初始化方法。
文章中有多有借鑒,只是用來作為個人備忘,如有冒犯,請聯系本人,謝謝