iOS中assign卵沉、copy 颠锉、retain等關(guān)鍵字區(qū)別、以及內(nèi)存中棧和堆的含義

舉個(gè)例子:

常見的寫法:
@property(atomic,retain,readwrite) Dog *dog;


1偎箫、第一個(gè)位置的值:
atomic:線程保護(hù)的木柬,默認(rèn)
nonatomic:線程不保護(hù)的
2、第二個(gè)位置的值:
assign:直接賦值淹办,默認(rèn)
retain:保留對(duì)象,內(nèi)部會(huì)自動(dòng)調(diào)用retain方法眉枕,引用計(jì)數(shù)+1
copy:拷貝對(duì)象
3、第三個(gè)位置的值:
readwrite:生成get/set方法,默認(rèn)
readonly:只生成get方法

主要是第二位置的值不易區(qū)分速挑,接下來我們看看

1.關(guān)于assign谤牡、copy 、retain等關(guān)鍵字之間含義和區(qū)別姥宝?

assign: 簡(jiǎn)單賦值翅萤,不更改索引計(jì)數(shù)
copy: 建立一個(gè)索引計(jì)數(shù)為1的對(duì)象,然后釋放舊對(duì)象
retain:釋放舊的對(duì)象腊满,將舊對(duì)象的值賦予輸入對(duì)象套么,再提高輸入對(duì)象的索引計(jì)數(shù)為1
區(qū)別:
Copy其實(shí)是建立了一個(gè)相同的對(duì)象,而retain不是:
比如: 一個(gè)NSString對(duì)象碳蛋,地址為0×1111胚泌,內(nèi)容為@”STR”
Copy到另外一個(gè)NSString之 后,開辟一片新內(nèi)存空間來存儲(chǔ)肃弟,地址為0×2222玷室,內(nèi)容相同,新的對(duì)象retain為1笤受, 舊有對(duì)象沒有變化
retain到另外一個(gè)NSString之 后穷缤,地址相同(建立一個(gè)指針,指針拷貝)箩兽,內(nèi)容當(dāng)然相同津肛,這個(gè)對(duì)象的retain值+1
也就是說,retain是指針拷貝汗贫,copy是內(nèi)容拷貝快耿。在拷貝之前,都會(huì)釋放舊的對(duì)象芳绩。

  • 使用assign: 對(duì)基礎(chǔ)數(shù)據(jù)類型 (NSInteger)和C數(shù)據(jù)類型(int, float, double, char,等)
  • 使用copy: 對(duì)NSString
  • 使用retain: 對(duì)其他NSObject和其子類

舉個(gè)例子:

    NSString *houseOfMM = [[NSString alloc] initWithString:'北京別墅房']; 

上面一段代碼會(huì)執(zhí)行以下兩個(gè)動(dòng)作:
1 在堆上分配一段內(nèi)存用來存儲(chǔ)@"北京別墅房 " ,比如:內(nèi)存地址為 0X1111 內(nèi)容為 '"北京別墅房" ,
2 在棧上分配一段內(nèi)存用來存儲(chǔ) houseOfMM ,比如:地址為 0XAAAA 內(nèi)容自然為 0X1111 下面分別看下(assign,retain,copy):
1.assign的情況:

 NSString  * myHouse  = [ houseOfMM   assign ];  

此時(shí) myHouse 和 houseOfMM 完全相同,地址都是 0XAAAA ,
內(nèi)容為 0X1111 ,即 myHouse 只是 houseOfMM 的別名,對(duì)任何一個(gè)操作就等于對(duì)另一個(gè)操作撞反。
因此 retainCount 不需要增加.(同進(jìn)同出妥色,關(guān)系好,一把鑰匙遏片,給我拿著)

2.retain的情況:

 NSString  *  myHouse  = [ houseOfMM   retain ]; 

此時(shí) myHouse 的地址不再為 0XAAAA ,可能為 0XAABB ,但是內(nèi)容依然為 0X1111 .
因此 myHouse 和 houseOfMM 都可以管理' 北京別墅房 '所在的內(nèi)存嘹害。
因此 retainCount 需要增加1.(有些獨(dú)立,各自進(jìn)出吮便,兩把鑰匙)
3.copy的情況(這樣說并不精準(zhǔn)笔呀,文中沒有過多對(duì)深淺copy詳述,這里補(bǔ)充下:
針對(duì)不可變對(duì)象調(diào)用copy返回該對(duì)象本身髓需,調(diào)用mutableCopy返回一個(gè)可變對(duì)象(新的)许师;
針對(duì)可變對(duì)象調(diào)用copy返回一個(gè)不可變對(duì)象(新的),調(diào)用mutableCopy返回另外一個(gè)可變對(duì)象(新的)。也就是說只有不可變對(duì)象copy時(shí)才會(huì)發(fā)生指針拷貝):

NSString  *  myHouse  = [ houseOfMM   mutableCopy]; 

此時(shí)會(huì)在堆上重新開辟一段內(nèi)存存放@'北京別墅房',比如0X1122,
內(nèi)容為@'北京別墅房',同時(shí)會(huì)在棧上為myHouse分配空間,比如地址:0XAACC,內(nèi)容為0X1122,
因此retainCount增加1供myHouse來管理0X1122這段內(nèi)存.(兩套@'北京別墅房')

注: ARC中的strong相當(dāng)于非ARC中的retain微渠,ARC來了以后多搞一把鑰匙就strong了啦搭幻。

看到這,或許有人會(huì)上文中對(duì)棧和堆的有些疑惑逞盆, 接下來是轉(zhuǎn)一位大神很經(jīng)典的談棧和堆檀蹋,來一起看看,更能理解上面的含義:

一云芦、預(yù)備知識(shí)—程序的內(nèi)存分配

一個(gè)由C/C++編譯的程序占用的內(nèi)存分為以下幾個(gè)部分
1俯逾、棧區(qū)(stack)— 由編譯器自動(dòng)分配釋放 ,存放函數(shù)的參數(shù)值舅逸,局部變量的值等桌肴。其 操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

2堡赔、堆區(qū)(heap) — 一般由程序員分配釋放识脆, 若程序員不釋放,程序結(jié)束時(shí)可能由OS回收 善已。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事灼捂,分配方式倒是類似于鏈表

3、全局區(qū)(靜態(tài)區(qū))(static)—换团,全局變量和靜態(tài)變量的存儲(chǔ)是放在一塊的悉稠,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另 一塊區(qū)域艘包。 - 程結(jié)束后由系統(tǒng)釋放的猛。

4、**文字常量區(qū) ** —常量字符串就是放在這里的想虎。 程序結(jié)束后由系統(tǒng)釋放

5卦尊、程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。

二舌厨、例子程序

這是一個(gè)前輩寫的岂却,非常詳細(xì)

  //main.cpp   
  int   a   =   0;   全局初始化區(qū)   
  char   *p1;   全局未初始化區(qū)   
  main()   
  {   
  int   b;   棧   
  char   s[]   =   "abc";   棧   
  char   *p2;   棧   
  char   *p3   =   "123456";   123456/0在常量區(qū),p3在棧上裙椭。   
  static   int   c   =0躏哩;   全局(靜態(tài))初始化區(qū)   
  p1   =   (char   *)malloc(10);   
  p2   =   (char   *)malloc(20);   
  分配得來得10和20字節(jié)的區(qū)域就在堆區(qū)。   
  strcpy(p1,   "123456");   123456/0放在常量區(qū)揉燃,編譯器可能會(huì)將它與p3所指向的"123456" 
  優(yōu)化成一個(gè)地方扫尺。   
  }   

三、堆和棧的理論知識(shí)

2.1申請(qǐng)方式

stack:
由系統(tǒng)自動(dòng)分配炊汤。 例如正驻,聲明在函數(shù)中一個(gè)局部變量 int b; 系統(tǒng)自動(dòng)在棧中為b開辟空間
heap:
需要程序員自己申請(qǐng)弊攘,并指明大小,在c中malloc函數(shù)
如p1 = (char *)malloc(10);
在C++中用new運(yùn)算符
如p2 = new char[10];
但是注意p1拨拓、p2本身是在棧中的肴颊。

2.2 申請(qǐng)后系統(tǒng)的響應(yīng)

棧:只要棧的剩余空間大于所申請(qǐng)空間,系統(tǒng)將為程序提供內(nèi)存渣磷,否則將報(bào)異常提示棧溢 出婿着。
堆:首先應(yīng)該知道操作系統(tǒng)有一個(gè)記錄空閑內(nèi)存地址的鏈表,當(dāng)系統(tǒng)收到程序的申請(qǐng)時(shí)醋界, 會(huì)遍歷該鏈表竟宋,尋找第一個(gè)空間大于所申請(qǐng)空間的堆結(jié)點(diǎn),然后將該結(jié)點(diǎn)從空閑結(jié)點(diǎn)鏈表 中刪除形纺,并將該結(jié)點(diǎn)的空間分配給程序丘侠,另外,對(duì)于大多數(shù)系統(tǒng)逐样,會(huì)在這塊內(nèi)存空間中的 首地址處記錄本次分配的大小蜗字,這樣,代碼中的delete語句才能正確的釋放本內(nèi)存空間脂新。
另外挪捕,由于找到的堆結(jié)點(diǎn)的大小不一定正好等于申請(qǐng)的大小,系統(tǒng)會(huì)自動(dòng)的將多余的那部分重新放入空閑鏈表中争便。

2.3 申請(qǐng)大小的限制

:在Windows下,棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu)级零,是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的滞乙,在WINDOWS下奏纪,棧的大小是2M(也有 的說是1M,總之是一個(gè)編譯時(shí)就確定的常數(shù))斩启,如果申請(qǐng)的空間超過棧的剩余空間時(shí)序调,將 提示overflow。因此兔簇,能從棧獲得的空間較小炕置。

:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域男韧。這是由于系統(tǒng)是用鏈表來存儲(chǔ) 的空閑內(nèi)存地址的,自然是不連續(xù)的默垄,而鏈表的遍歷方向是由低地址向高地址此虑。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見口锭,堆獲得的空間比較靈活朦前,也比較大介杆。

2.4 申請(qǐng)效率的比較:

棧由系統(tǒng)自動(dòng)分配,速度較快韭寸。但程序員是無法控制的春哨。
堆是由new分配的內(nèi)存,一般速度比較慢恩伺,而且容易產(chǎn)生內(nèi)存碎片,不過用起來最方便.
另外赴背,在WINDOWS下,最好的方式是用VirtualAlloc分配內(nèi)存晶渠,他不是在堆凰荚,也不是在棧是
直接在進(jìn)程的地址空間中保留一塊內(nèi)存,雖然用起來最不方便褒脯。但是速度快便瑟,也最靈活。

2.5 堆和棧中的存儲(chǔ)內(nèi)容

棧: 在函數(shù)調(diào)用時(shí)番川,第一個(gè)進(jìn)棧的是主函數(shù)中后的下一條指令(函數(shù)調(diào)用語句的下一條可
執(zhí)行語句)的地址到涂,然后是函數(shù)的各個(gè)參數(shù),在大多數(shù)的C編譯器中颁督,參數(shù)是由右往左入棧
的践啄,然后是函數(shù)中的局部變量。注意靜態(tài)變量是不入棧的适篙。
當(dāng)本次函數(shù)調(diào)用結(jié)束后往核,局部變量先出棧,然后是參數(shù)嚷节,最后棧頂指針指向最開始存的地
址聂儒,也就是主函數(shù)中的下一條指令,程序由該點(diǎn)繼續(xù)運(yùn)行硫痰。
堆:一般是在堆的頭部用一個(gè)字節(jié)存放堆的大小衩婚。堆中的具體內(nèi)容由程序員安排。

2.6存取效率的比較
char   s1[]   =   "aaaaaaaaaaaaaaa";   
char   *s2   =   "bbbbbbbbbbbbbbbbb";   

aaaaaaaaaaa是在運(yùn)行時(shí)刻賦值的效斑;
而bbbbbbbbbbb是在編譯時(shí)就確定的非春;
但是,在以后的存取中缓屠,在棧上的數(shù)組比指針?biāo)赶虻淖址?例如堆)快奇昙。

比如:

  #include   
  void   main()   
  {   
  char   a   =   1;   
  char   c[]   =   "1234567890";   
  char   *p   ="1234567890";   
  a   =   c[1];   
  a   =   p[1];   
  return;   
  }   
  對(duì)應(yīng)的匯編代碼   
  10:   a   =   c[1];   
  00401067   8A   4D   F1   mov   cl,byte   ptr   [ebp-0Fh]   
  0040106A   88   4D   FC   mov   byte   ptr   [ebp-4],cl   
  11:   a   =   p[1];   
  0040106D   8B   55   EC   mov   edx,dword   ptr   [ebp-14h]   
  00401070   8A   42   01   mov   al,byte   ptr   [edx+1]   
  00401073   88   45   FC   mov   byte   ptr   [ebp-4],al   
  第一種在讀取時(shí)直接就把字符串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到 
  edx中敌完,再根據(jù)edx讀取字符储耐,顯然慢了。   
2.7小結(jié):

堆和棧的區(qū)別可以用如下的比喻來看出:
使用棧就象我們?nèi)ワ堭^里吃飯滨溉,只管點(diǎn)菜(發(fā)出申請(qǐng))什湘、付錢长赞、和吃(使用),吃飽了就走闽撤,不必理會(huì)切菜得哆、洗菜等準(zhǔn)備工作和洗碗、刷鍋等掃尾工作哟旗,他的好處是快捷贩据,但是自由度小。
使用堆就象是自己動(dòng)手做喜歡吃的菜肴热幔,比較麻煩乐设,但是比較符合自己的口味,而且自由度大绎巨。
對(duì)了近尚,還有一個(gè)問題,凡事會(huì)問為什么? 為什么NSString 用copy, 數(shù)值用assion...等 ?
這個(gè)愛問為什么的小明同學(xué) 知乎上也有給你解答: https://www.zhihu.com/question/20102376 场勤、http://blog.csdn.net/itianyi/article/details/9018567
其他奧秘需要你自己動(dòng)手動(dòng)腦解決吧戈锻!``

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市和媳,隨后出現(xiàn)的幾起案子格遭,更是在濱河造成了極大的恐慌,老刑警劉巖留瞳,帶你破解...
    沈念sama閱讀 223,002評(píng)論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拒迅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡她倘,警方通過查閱死者的電腦和手機(jī)璧微,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來硬梁,“玉大人前硫,你說我怎么就攤上這事∮梗” “怎么了屹电?”我有些...
    開封第一講書人閱讀 169,787評(píng)論 0 365
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)跃巡。 經(jīng)常有香客問我危号,道長(zhǎng),這世上最難降的妖魔是什么素邪? 我笑而不...
    開封第一講書人閱讀 60,237評(píng)論 1 300
  • 正文 為了忘掉前任葱色,我火速辦了婚禮,結(jié)果婚禮上娘香,老公的妹妹穿的比我還像新娘苍狰。我一直安慰自己,他們只是感情好烘绽,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,237評(píng)論 6 398
  • 文/花漫 我一把揭開白布淋昭。 她就那樣靜靜地躺著,像睡著了一般安接。 火紅的嫁衣襯著肌膚如雪翔忽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,821評(píng)論 1 314
  • 那天盏檐,我揣著相機(jī)與錄音歇式,去河邊找鬼。 笑死胡野,一個(gè)胖子當(dāng)著我的面吹牛材失,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播硫豆,決...
    沈念sama閱讀 41,236評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼龙巨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了熊响?” 一聲冷哼從身側(cè)響起旨别,我...
    開封第一講書人閱讀 40,196評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎汗茄,沒想到半個(gè)月后秸弛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,716評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡洪碳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,794評(píng)論 3 343
  • 正文 我和宋清朗相戀三年递览,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片偶宫。...
    茶點(diǎn)故事閱讀 40,928評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡非迹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纯趋,到底是詐尸還是另有隱情憎兽,我是刑警寧澤,帶...
    沈念sama閱讀 36,583評(píng)論 5 351
  • 正文 年R本政府宣布吵冒,位于F島的核電站纯命,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏痹栖。R本人自食惡果不足惜亿汞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,264評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望揪阿。 院中可真熱鬧疗我,春花似錦咆畏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至麦牺,卻和暖如春钮蛛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剖膳。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工魏颓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吱晒。 一個(gè)月前我還...
    沈念sama閱讀 49,378評(píng)論 3 379
  • 正文 我出身青樓甸饱,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親枕荞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子柜候,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,937評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容