一悔据、簡介
深入了解ARC墓卦,主要從一下幾個修飾符深入了解 __strong/__weak/_atuoreleasing
1票摇、__strong
首先時當(dāng)編譯器初始化strong類型對象時化焕,編譯器偽代碼如下
id obj = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(obj,@selector(init));
objc_release(obj);
生成對象時烛亦,是以消息發(fā)送的方式去分配內(nèi)存空間和對象左腔,后用release方法釋放對象唧垦,當(dāng)為ARC時不需顯示調(diào)用release方法,編譯器會插入該方法翔悠。
相對于系統(tǒng)的 alloc/new/copy/mutablecopy 來說
另一些方法初始化如:id obj=[NSMutableArray array];
id obj = objc_msgSend(NSObject,@selector(alloc));
objc_retainAutoreleasedReturnVlaue(obj); //編譯器插入 用于優(yōu)化程序业崖,相對應(yīng)的成對get方法時使用:objc_autoreleaseReturnValue(obj); 通過該過程的兩個方法 在初始化和獲取后調(diào)用野芒,就不必將對象注冊autoreleaspool中,而是直接返回該對象双炕,優(yōu)化了運行程序時間及步驟
objc_release(obj);?
2狞悲、__weak修飾符
有weak 初始化的對象,是不能被持有妇斤,會被立即釋放摇锋;編譯器會生成一個全局的弱引用表;當(dāng)對弱引用對象操作時不會做引用計數(shù)加減操作站超;
編譯器釋放弱引用對象是怎樣的
1)從weak表中獲取釋放對象的地址為鍵值的記錄
2)將記錄的__weak修飾的變量地址荸恕,并賦值為nil;并從表中刪除該記錄
初始化對象時死相,不可直接 用__weak 否則會直接被釋放
注意:如沒循環(huán)引用建議不要插入weak融求,大量操作會影響cpu性能
3、__autorelease修飾符
用該修飾符初始化的對象算撮,等同于在mrc 中生宛,插入了autorelease;使得對象在不使用時能得以釋放
知識點補充:
深拷貝淺拷貝
理解NSString使用copy及strong修飾的原理
1. copy出來的字符串一定是不可變字符串肮柜,如果傳入的是可變字符串陷舅,會發(fā)生深拷貝為不可變字符串,否則為淺拷貝审洞。
2. mutablecopy莱睁,一定是深拷貝,拷貝出來的一定是可變字符串或者數(shù)組芒澜,即使傳入的是不可變字符串或者數(shù)組仰剿。
理解:
為什么NSString使用copy修飾也就可以理解了。使用copy修飾之后痴晦,即使屬性拷貝來自可變字符串酥馍,也會被深拷貝成不可變字符串,也就是源字符串修改之后不會影響到屬性字符串阅酪,增強了代碼的健壯性。
關(guān)于不可變字符串和數(shù)組的copy是淺拷貝也很好理解汁针,既然數(shù)據(jù)源本身是不可變的术辐,也就是具備安全性,那么系統(tǒng)默認(rèn)淺拷貝其中數(shù)據(jù)施无,顯然是合理的做法辉词。
Tagged Pointer技術(shù),用于優(yōu)化NSNumber猾骡、NSDate瑞躺、NSString等小對象的存儲,使用Tagged Pointer之后敷搪,NSNumber指針里面存儲的數(shù)據(jù)變成了:Tag + Data,也就是將數(shù)據(jù)直接存儲在了指針中那么他就不是一個對象了幢哨。
1 當(dāng)字符串很短的時候iOS會使用Tagged Pointer對NSString進(jìn)行優(yōu)化赡勘,此時NSString內(nèi)存地址是Tag + Data,那么它就不是一個對象了捞镰,因此它也就沒有setName方法闸与,所以他也就不會調(diào)用setName方法而是直接賦值
2 那么當(dāng)字符串很長,那么就不會使用Tagged Pointer技術(shù)岸售,那么他就是一個普通的字符串對象践樱,當(dāng)開啟多個線程并行調(diào)用setName方法時在調(diào)用[_name release];時有可能_name已經(jīng)被上一個線程給release過了,它的引用計數(shù)為零了凸丸,那么這是再有一個線程調(diào)用release就會報壞內(nèi)存訪問拷邢。解決辦法就是name聲明成atomic,或者在調(diào)用self.name時加鎖。