屬性關(guān)鍵字-(進(jìn)階篇)

上一篇文章基礎(chǔ)篇,我們用NSMutableString為例詳細(xì)講解了“非容器可變變量”夹供。相信大家都已經(jīng)基本掌握了重點(diǎn)在不同關(guān)鍵字的定義下堕义,它們有何相同以及不同之處扬跋。
但通過上一篇我們只了解了主題的一半內(nèi)容而已桩砰,接下來內(nèi)容可能有點(diǎn)多拓春,不過知識(shí)點(diǎn)和內(nèi)容與上一篇大同小異。
如果你有仔細(xì)學(xué)習(xí)基礎(chǔ)篇亚隅,那么進(jìn)階篇學(xué)起來會(huì)Very Easy痘儡。

一. 今天我們先用NSMutableArray舉例來講解容器可變變量

@property(nonatomic, copy)  NSMutableArray *arrayCopy;
@property(nonatomic, strong)NSMutableArray *arrayStrong;
@property(nonatomic, weak)  NSMutableArray *arrayWeak;

- (void)viewDidLoad {
    
    [super viewDidLoad];
    NSMutableArray *testArray = [[NSMutableArray alloc] init];
    NSMutableString *str1 = [[NSMutableString alloc]initWithString:@"test1"];
    NSMutableString *str2 = [[NSMutableString alloc]initWithString:@"test2"];
    
    [testArray addObject:str1];
    [testArray addObject:str2];
    
    self.arrayCopy= testArray;
    self.arrayStrong= testArray;
    self.arrayWeak= testArray;
    
    NSLog(@"testArray   輸出:%p, %@", testArray,testArray);
    NSLog(@"arrayCopy   輸出:%p, %@",_arrayCopy,_arrayCopy);
    NSLog(@"arrayStrong 輸出:%p, %@",_arrayStrong,_arrayStrong);
    NSLog(@"arrayWeak   輸出:%p, %@",_arrayWeak,_arrayWeak);
    NSLog(@"arrayWeak   輸出:%p, %@",_arrayWeak[0],_arrayWeak[0]);
    NSLog(@"testArray中的數(shù)據(jù)引用計(jì)數(shù)%@", [testArray valueForKey:@"retainCount"]);
    // 輸出內(nèi)容
    testArray   輸出:0x604000441470, ( test1, test2 )
    arrayCopy   輸出:0x60400022a140, ( test1, test2 )
    arrayStrong 輸出:0x604000441470, ( test1, test2 )
    arrayWeak   輸出:0x604000441470, ( test1, test2 )
    arrayWeak   輸出:0x604000441470, test1
    testArray中的數(shù)據(jù)引用計(jì)數(shù)( 3, 3 )
}
  • 這里只有arrayCopy的地址發(fā)生了變化枢步,說明arrayCopy為深拷貝沉删,它會(huì)重新開辟一塊內(nèi)存來創(chuàng)建一塊新容器。但新的容器內(nèi)copy來的兩個(gè)元素指為淺拷貝醉途,指針的指向還是str1矾瑰、str2,這樣就會(huì)使str1隘擎、str2的地址的引用計(jì)數(shù)+1殴穴。
  • arrayWeak、arrayStrong都是淺拷貝货葬、不會(huì)開辟新的內(nèi)存采幌,也不會(huì)使容器內(nèi)部的元素引用計(jì)數(shù)增加。
接下來我們來給測(cè)試數(shù)組添加一個(gè)元素
NSMutableString *str3 = [[NSMutableString alloc]initWithString:@"test3"];
    [testArray addObject:str3];
    NSLog(@"testArray   輸出:%p, %@", testArray,testArray);
    NSLog(@"arrayCopy   輸出:%p, %@",_arrayCopy,_arrayCopy);
    NSLog(@"arrayStrong 輸出:%p, %@",_arrayStrong,_arrayStrong);
    NSLog(@"arrayWeak   輸出:%p, %@",_arrayWeak,_arrayWeak);
    NSLog(@"testArray中的數(shù)據(jù)引用計(jì)數(shù)%@", [testArray valueForKey:@"retainCount"]);
    // 輸出內(nèi)容
    testArray    輸出:0x604000441470, ( test1, test2, test3 )
    arrayCopy    輸出:0x60400022a140, ( test1, test2 )
    arrayStrong  輸出:0x604000441470, ( test1, test2, test3 )
    arrayWeak    輸出:0x604000441470, ( test1, test2, test3 )
    testArray中的數(shù)據(jù)引用計(jì)數(shù)(3, 3, 2)
從結(jié)果可以看出
  • 只有arrayCopy內(nèi)的元素沒有增加震桶,因?yàn)樗切麻_辟的內(nèi)存創(chuàng)建的容器休傍,容器內(nèi)只有原來兩個(gè)元素并指向兩個(gè)元素的地址。
  • arrayStrong蹲姐、arrayWeak都是直接指向testArray的內(nèi)存地址磨取,所以也會(huì)隨著testArray的改變而改變。
我們最后來修改原數(shù)組中的元素柴墩,看是否其他數(shù)組會(huì)隨之變化
    [str1 appendFormat:@"abc"];
    
    NSLog(@"testArray   輸出:%p, %@", testArray,testArray);
    NSLog(@"arrayCopy   輸出:%p, %@",_arrayCopy,_arrayCopy);
    NSLog(@"arrayStrong 輸出:%p, %@",_arrayStrong,_arrayStrong);
    NSLog(@"arrayWeak   輸出:%p, %@",_arrayWeak,_arrayWeak);

    // 輸出內(nèi)容
     testArray   輸出:0x604000441470, ( test1abc, test2, test3 )
     arrayCopy   輸出:0x60400022a140, ( test1abc, test2 )
     arrayStrong 輸出:0x604000441470, ( test1abc, test2, test3 )
     arrayWeak   輸出:0x604000441470, ( test1abc, test2, test3 )

容器可變變量總結(jié)

  • 修改原數(shù)組中的元素后忙厌,我們看到arrayStrongarrayWeak江咳、arrayCopy內(nèi)部的元素都發(fā)生了變化逢净,
  • 這說明"容器可變變量中的元素"在拷貝過程中無論CopyWeak歼指、Strong都是淺拷貝爹土。
  • 但"容器可變變量的容器本身"只有Copy是深拷貝,其余Weak东臀、Strong都是淺拷貝着饥。
二. 非容器不變變量
@property (nonatomic, copy)   NSString *stringCopy;
@property (nonatomic, strong) NSString *stringStrong;
@property (nonatomic, weak)   NSString *stringWeak;
@property (nonatomic, assign) NSString *stringAssign;

- (void)p_TestCode
{
    NSString *testStr = [[NSString alloc] initWithUTF8String:"testCode123456"];

    self.stringCopy = testStr;
    self.stringWeak = testStr;
    self.stringStrong = testStr;
    self.stringAssign = testStr;

    NSLog(@"testStr     輸出:%p,%@", testStr,testStr);
    NSLog(@"stringCopy  輸出:%p,%@",_stringCopy,_stringCopy);
    NSLog(@"stringStrong輸出:%p,%@",_stringStrong,_stringStrong);
    NSLog(@"stringWeak  輸出:%p,%@",_stringWeak,_stringWeak);
    NSLog(@"testStr中的數(shù)據(jù)引用計(jì)數(shù)%@", [testStr valueForKey:@"retainCount"]);

    // 輸出內(nèi)容
    testStr      輸出:0xa001003046c32808,testCode
    stringCopy   輸出:0xa001003046c32808,testCode
    stringStrong 輸出:0xa001003046c32808,testCode
    stringWeak   輸出:0xa001003046c32808,testCode
}
  • 賦值后stringCopy犀农、stringStrong惰赋、stringWeak的指針都指向testStr的地址。
  • 此時(shí)我們testStr的引用計(jì)數(shù)應(yīng)該為3,copy為淺拷貝赁濒,不開辟新的存儲(chǔ)空間轨奄,但指向的內(nèi)存地址引用計(jì)數(shù)+1。
接下來我們給testStr重新賦值拒炎,來看下面的代碼
testStr = @"abc";

NSLog(@"testStr     輸出:%p,%@", testStr,testStr);
NSLog(@"stringCopy  輸出:%p,%@",_stringCopy,_stringCopy);
NSLog(@"stringStrong輸出:%p,%@",_stringStrong,_stringStrong);
NSLog(@"stringWeak  輸出:%p,%@",_stringWeak,_stringWeak);
NSLog(@"testStr     引用計(jì)數(shù)%@", [testStr valueForKey:@"retainCount"]);

 // 輸出內(nèi)容
 testStr      輸出:0x103806110,aaa
 stringCopy   輸出:0xa001003046c32808,testCode
 stringStrong 輸出:0xa001003046c32808,testCode
 stringWeak   輸出:0xa001003046c32808,testCode
  • stringCopy挪拟、stringStrong、stringWeak指向的地址和值仍然是testStr重新賦值之前的击你。
  • 細(xì)心的同學(xué)可能會(huì)發(fā)現(xiàn)當(dāng)我們重新給testStr賦值時(shí)玉组,testStr就指向了一塊新的存儲(chǔ)空間,但是原有內(nèi)存地址引用計(jì)數(shù)為3丁侄,-1后扔為2惯雳,并不能釋放掉這塊內(nèi)存。所以就解釋了為什么testStr已經(jīng)不指向原有內(nèi)存地址了鸿摇,但并沒有影響其他成員的值石景。
我們?cè)賮砜聪旅娴拇a
self.stringCopy=nil;
self.stringStrong=nil;

NSLog(@"testStr     輸出:%p,%@", testStr,testStr);
NSLog(@"stringCopy  輸出:%p,%@",_stringCopy,_stringCopy);
NSLog(@"stringStrong輸出:%p,%@",_stringStrong,_stringStrong);
NSLog(@"stringWeak  輸出:%p,%@",_stringWeak,_stringWeak);
NSLog(@"testStr     引用計(jì)數(shù)%@", [testStr valueForKey:@"retainCount"]);

 // 輸出內(nèi)容
 testStr     輸出:0x103806110,aaa
 stringCopy  輸出:0x0,(null)
 stringStrong輸出:0x0,(null)
 stringWeak  輸出:0x0,(null)
  • stringCopystringStrong設(shè)為nil后拙吉,發(fā)現(xiàn)stringWeak隨之改為nil潮孽。
  • 因?yàn)楫?dāng)testStr重新賦值后,原來指向的內(nèi)存地址引用計(jì)數(shù)變?yōu)?code>3-1=2筷黔,當(dāng)stringCopy往史、stringStrong置空后引用計(jì)數(shù)為2-2=0。所以weak自然也是null佛舱。
非容器不變變量總結(jié)
  • 不難看出NSString(非容器不可變變量) 和NSMutableString(非容器可變變量) 基本相同怠堪。
  • 除了copy不可變變量為淺拷貝,可變變量為深拷貝名眉。那為什么copy不可變變量不自己開辟一個(gè)獨(dú)立的內(nèi)存出來呢粟矿?
  • 原因很簡單,因?yàn)椴豢勺冏兞康?strong>值不會(huì)改變损拢,所以系統(tǒng)覺得沒必要再開辟一個(gè)內(nèi)存出來讓stringCopy指向它陌粹,直接指向原來的內(nèi)存地址就可以了。

三. 不可變?nèi)萜髯兞颗e例NSArray

@property(nonatomic, copy)  NSArray *arrayCopy;
@property(nonatomic, strong)NSArray *arrayStrong;
@property(nonatomic, weak)  NSArray *arrayWeak;

NSString *str1 = [[NSMutableString alloc]initWithString:@"test1"];
NSString *str2 = [[NSMutableString alloc]initWithString:@"test2"];

NSArray *testArray = [[NSArray alloc] initWithObjects:str1,str2, nil];

self.arrayCopy= testArray;
self.arrayStrong= testArray;
self.arrayWeak= testArray;

NSLog(@"testArray   輸出:%p, %@", testArray,testArray);
NSLog(@"arrayCopy   輸出:%p, %@",_arrayCopy,_arrayCopy);
NSLog(@"arrayStrong 輸出:%p, %@",_arrayStrong,_arrayStrong);
NSLog(@"arrayWeak   輸出:%p, %@",_arrayWeak,_arrayWeak);
NSLog(@"testArray中的數(shù)據(jù)引用計(jì)數(shù)%@", [testArray valueForKey:@"retainCount"]);
// 輸出內(nèi)容
testArray   輸出:0x60400042a460, ( test1, test2 )
arrayCopy   輸出:0x60400042a460, ( test1, test2 )
arrayStrong 輸出:0x60400042a460, ( test1, test2 )
arrayWeak   輸出:0x60400042a460, ( test1, test2 )
testArray中的數(shù)據(jù)引用計(jì)數(shù)( 2, 2 )
  • 在不可變?nèi)萜髯兞恐校?strong>容器本身都是淺拷貝包括copy福压,同NSString掏秩。
  • CopyStrong荆姆、Weak蒙幻、Assign都是淺拷貝都不會(huì)增加容器內(nèi)部元素的引用計(jì)數(shù)

以下為全篇總結(jié):Copy胆筒、Strong邮破、Assgin诈豌、Weak

可變變量中:
  • Copy會(huì)開辟一塊新的內(nèi)存抒和;而Strong矫渔、AssginWeak不會(huì)摧莽,他們只是將指針指向保存值的內(nèi)存對(duì)應(yīng)的地址庙洼;
  • Strong會(huì)再指向地址后對(duì)該內(nèi)存引用計(jì)數(shù)+1
  • Weak镊辕、Assgin不會(huì)增加引用計(jì)數(shù)油够,但會(huì)在指向的地址引用計(jì)數(shù)為0時(shí)將值置為空,并且Weak會(huì)將內(nèi)存置為nil征懈,而Assgin不會(huì)叠聋,Assgin會(huì)在內(nèi)存被重寫之前繼續(xù)輸出,一旦內(nèi)存被重寫后會(huì)引起程序崩潰受裹。
不可變變量中:

變量本身不可修改碌补,Copy沒有必要開辟一塊新的內(nèi)存存放一摸一樣的內(nèi)容,所以默認(rèn)為淺拷貝棉饶。
Strong厦章、AssginWeak則和可變變量保持一致照藻。

容器:

容器本身遵守上面可變與不可變的原則袜啃,只是內(nèi)部元素只會(huì)被淺拷貝


關(guān)于屬性關(guān)鍵字Zombie就先聊到這.歡迎大家一起討論.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末幸缕,一起剝皮案震驚了整個(gè)濱河市群发,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌发乔,老刑警劉巖熟妓,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異栏尚,居然都是意外死亡起愈,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門译仗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抬虽,“玉大人,你說我怎么就攤上這事纵菌〔郏” “怎么了?”我有些...
    開封第一講書人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵咱圆,是天一觀的道長笛辟。 經(jīng)常有香客問我功氨,道長,這世上最難降的妖魔是什么隘膘? 我笑而不...
    開封第一講書人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮杠览,結(jié)果婚禮上弯菊,老公的妹妹穿的比我還像新娘。我一直安慰自己踱阿,他們只是感情好管钳,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著软舌,像睡著了一般才漆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上佛点,一...
    開封第一講書人閱讀 52,549評(píng)論 1 312
  • 那天醇滥,我揣著相機(jī)與錄音,去河邊找鬼超营。 笑死鸳玩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的演闭。 我是一名探鬼主播不跟,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼米碰!你這毒婦竟也來了窝革?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤吕座,失蹤者是張志新(化名)和其女友劉穎虐译,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吴趴,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡菱蔬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了史侣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拴泌。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖惊橱,靈堂內(nèi)的尸體忽然破棺而出蚪腐,到底是詐尸還是另有隱情,我是刑警寧澤税朴,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布回季,位于F島的核電站家制,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏泡一。R本人自食惡果不足惜颤殴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鼻忠。 院中可真熱鬧涵但,春花似錦、人聲如沸帖蔓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽塑娇。三九已至澈侠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間埋酬,已是汗流浹背哨啃。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留写妥,地道東北人棘催。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像耳标,于是被迫代替她去往敵國和親醇坝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361

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

  • 原子性 原子性就nonatomic和atomic兩個(gè)關(guān)鍵字 atomic與nonatomic atomic是默認(rèn)的...
    薩繆閱讀 382評(píng)論 0 2
  • 本文邏輯圖: 在知道他們區(qū)別之前次坡,我們首先要知道NSObject對(duì)象的賦值操作做了哪些操作呼猪。 A=C其實(shí)是在內(nèi)存中...
    壯了個(gè)壯閱讀 20,814評(píng)論 40 148
  • 之前寫過 《iOS屬性關(guān)鍵字》基礎(chǔ)篇,便于初學(xué)者理解砸琅,但沒有從根本上去說明宋距,屬性的本質(zhì),這次就更進(jìn)一步說明 屬性的...
    wnido閱讀 738評(píng)論 0 3
  • 307症脂、setValue:forKey和setObject:forKey的區(qū)別是什么谚赎? 答:1, setObjec...
    AlanGe閱讀 1,554評(píng)論 0 1
  • 平時(shí)的積累記錄下,記性差诱篷,方便平時(shí)查找 一 ARC和MRC的 小入門 1MRC在ARC之前壶唤,MRC就是傳統(tǒng)的手工內(nèi)...
    howhyone閱讀 376評(píng)論 0 0