iOS weak strong retain assign copy 屬性修飾 對比

前言:

在iOS 開發(fā)中 我們經(jīng)常用到 weak strong retain assign copy 屬性的修飾,他們的區(qū)別本質(zhì)上是?1.是否開辟新的內(nèi)存

2.是否對地址C有引用計數(shù)增加 的區(qū)別。

參考簡書:?http://www.reibang.com/p/a29a0bdd5da8??启绰。 筆者主要分三個 部分來介紹區(qū)別俯艰。

第一 是? 非容器 可變變量 的修飾 如NSMutableString? ?第二是? 容器對象 也就是NSArray等 類型的? ?第三 是非容器不可變變量 的修飾 。 第四 是 Block 類型的修飾 來區(qū)分每個地方的區(qū)別骡澈。DEMO下載地址珍策。 建議下載demo 試試。?

代碼分析:

第一 是非容器 可變變量 的修飾 如NSMutableString

首先

- (void)memoryTest

{

NSMutableString*tempMStr = [[NSMutableStringalloc]initWithString:@"strValue"];

NSLog(@"tempMStr值地址:%p吭狡,tempMStr值%@,tempMStr值引用計數(shù)%@\\n", tempMStr,tempMStr,[tempMStr valueForKey:retainCountKey]);

//輸出tempMStr值地址:0x7a05f650尖殃,tempMStr值strValue,tempMStr值引用計數(shù)1

}

這個方法 提供一中 獲取 內(nèi)存地址 和 引用計數(shù)的方式 在 ARC 的情況下。 下面的每個方法都是 基于上述方法划煮。

這是一個 閃退的方法assign

可以發(fā)現(xiàn)在輸出assignMStr時會出現(xiàn)奔潰的情況送丰。原因是發(fā)送了野指針的情況。assign同weak般此,指向C并且計數(shù)不+1蚪战,但當(dāng)C地址引用計數(shù)為0時,assign不會對C地址進行B數(shù)據(jù)的抹除操作 也就是設(shè)置為 nil铐懊,只是進行值釋放邀桑。這就導(dǎo)致野指針存在,即當(dāng)這塊地址還沒寫上其他值前科乎,能輸出正常值壁畸,但一旦重新寫上數(shù)據(jù),該指針隨時可能沒有值,造成奔潰捏萍。

- (void)compareAssignAndWeak

{

NSMutableString*mstrOrigin = [[NSMutableStringalloc]initWithString:@"mstrOriginValue"];

self.assignMStr= mstrOrigin;

self.weakMStr= mstrOrigin;

mstrOrigin = [[NSMutableStringalloc]initWithString:@"mstrOriginChange3"];

NSLog(@"weakMStr輸出:%p,%@\\n",_weakMStr,_weakMStr);

NSLog(@"assignMStr輸出:%p,%@\\n",self.assignMStr,self.assignMStr);

}


/**

注意 引用計數(shù)的 和 修改不同 的值的情況

*/

- (void)testOne

{

//

NSMutableString*mstrOrigin = [[NSMutableStringalloc]initWithString:@"mstrOriginValue"];

// 有意思的 是retainCount是一個對象類型

NSLog(@"mstrOrigin 開始的引用計數(shù)%@",[mstrOrigin valueForKey:@"retainCount"]);

self.aCopyMStr= mstrOrigin;

self.strongMStr= mstrOrigin;

self.retainMStr= mstrOrigin;

self.weakMStr= mstrOrigin;

self.assignMStr= mstrOrigin;

//

NSLog(@"mstrOrigin輸出:%p,%@\\n", mstrOrigin,mstrOrigin);

NSLog(@"aCopyMStr輸出:%p,%@\\n",_aCopyMStr,_aCopyMStr);

NSLog(@"strongMStr輸出:%p,%@\\n",_strongMStr,_strongMStr);

NSLog(@"retainMStr輸出:%p,%@\\n",_retainMStr,_retainMStr);

NSLog(@"weakMStr輸出:%p,%@\\n",_weakMStr,_weakMStr);

NSLog(@"assignMStr輸出:%p,%@\\n",_assignMStr,_assignMStr);

NSLog(@"mstrOrigin 新的引用計數(shù)%@",[mstrOrigin valueForKey:@"retainCount"]);

NSLog(@"aCopyMStr 的引用計數(shù)是:%@",[_aCopyMStrvalueForKey:@"retainCount"]);

/*

mstrOrigin 開始的引用計數(shù)1

mstrOrigin輸出:0x60400004cab0,mstrOriginValue\n

aCopyMStr輸出:0x600000447c20,mstrOriginValue\n

strongMStr輸出:0x60400004cab0,mstrOriginValue\n

retainMStr輸出:0x60400004cab0,mstrOriginValue\n

weakMStr輸出:0x60400004cab0,mstrOriginValue\n

assignMStr輸出:0x60400004cab0,mstrOriginValue\n

mstrOrigin 新的引用計數(shù)3

aCopyMStr 的引用計數(shù)是:1

*/

/*

從上面可以看出copy 并沒有改變引用計數(shù)太抓,ratain ,Strong 使得引用計數(shù)分別 +1

*/

NSLog(@"-------------修改原值后 ----------------");

[mstrOriginappendString:@"+appendValue"];

NSLog(@"mstrOrigin輸出:%p,%@\\n", mstrOrigin,mstrOrigin);

NSLog(@"aCopyMStr輸出:%p,%@\\n",_aCopyMStr,_aCopyMStr);// 沒有改變

NSLog(@"strongMStr輸出:%p,%@\\n",_strongMStr,_strongMStr);

NSLog(@"retainMStr輸出:%p,%@\\n",_retainMStr,_retainMStr);

NSLog(@"weakMStr輸出:%p,%@\\n",_weakMStr,_weakMStr);

NSLog(@"assignMStr輸出:%p,%@\\n",_assignMStr,_assignMStr);

NSLog(@"----------------- 設(shè)置成nil--------------------");

mstrOrigin =nil;

NSLog(@"mstrOrigin輸出:%p,%@\\n", mstrOrigin,mstrOrigin);

NSLog(@"aCopyMStr輸出:%p,%@\\n",_aCopyMStr,_aCopyMStr);

NSLog(@"strongMStr輸出:%p,%@\\n",_strongMStr,_strongMStr);

NSLog(@"retainMStr輸出:%p,%@\\n",_retainMStr,_retainMStr);

NSLog(@"weakMStr輸出:%p,%@\\n",_weakMStr,_weakMStr);

NSLog(@"assignMStr輸出:%p,%@\\n",_assignMStr,_assignMStr);

NSLog(@"mstrOrigin 新的引用計數(shù)%@",[mstrOrigin valueForKey:@"retainCount"]);

NSLog(@"strongMStr 新的引用計數(shù)%@",[_strongMStrvalueForKey:@"retainCount"]);

NSLog(@"aCopyMStr 的引用計數(shù)是:%@",[_aCopyMStrvalueForKey:@"retainCount"]);

NSLog(@"assignMStr 的引用計數(shù)是:%@",[_assignMStrvalueForKey:@"retainCount"]);

// strong retain 等影響了weak assign 的對比

}

讀者? 注意一點 在這個?testOne 中打印信息?_assignMStr 這個值沒有奔潰 !A铊尽走敌! 為什么? 因為 strong 屬性 對mstrOrigin 的修飾 影響了 _assginMStr 造成 并沒有被釋放 逗噩。 也就不會有野指針的問題掉丽!? 這是筆者要說明的。和參考的簡書作者沒有 注意到的异雁。?

第二是容器對象 也就是NSArray等 類型的

- (void)arrTest

{

NSMutableArray*mArrOrigin = [[NSMutableArrayalloc]init];

NSMutableString*mstr1 = [[NSMutableStringalloc]initWithString:@"value1"];

NSMutableString*mstr2 = [[NSMutableStringalloc]initWithString:@"value2"];

NSMutableString*mstr3 = [[NSMutableStringalloc]initWithString:@"value3"];

[mArrOriginaddObject:mstr1];

[mArrOriginaddObject:mstr2];

//將mArrOrigin拷貝給aCopyMArr捶障,strongMArr,weakMArr

self.aCopyMArr= mArrOrigin;

self.strongMArr= mArrOrigin;

self.weakMArr= mArrOrigin;

NSLog(@"mArrOrigin輸出:%p,%@\\n", mArrOrigin,mArrOrigin);

NSLog(@"aCopyMArr輸出:%p,%@\\n",_aCopyMArr,_aCopyMArr);

NSLog(@"strongMArr輸出:%p,%@\\n",_strongMArr,_strongMArr);

NSLog(@"weakMArr輸出:%p,%@\\n",_weakMArr,_weakMArr);

NSLog(@"weakMArr輸出:%p,%@\\n",_weakMArr[0],_weakMArr[0]);

NSLog(@"mArrOrigin中的數(shù)據(jù)引用計數(shù)%@", [mArrOrigin valueForKey:@"retainCount"]);

NSLog(@"%p %p %p %p",&mArrOrigin,mArrOrigin,mArrOrigin[0],mArrOrigin[1]);

// 說明 weak 并沒有增加引用計數(shù)

//給原數(shù)組添加一個元素

[mArrOriginaddObject:mstr3];

NSLog(@"mArrOrigin輸出:%p,%@\\n", mArrOrigin,mArrOrigin);

NSLog(@"aCopyMArr輸出:%p,%@\\n",_aCopyMArr,_aCopyMArr);

NSLog(@"strongMArr輸出:%p,%@\\n",_strongMArr,_strongMArr);

NSLog(@"weakMArr輸出:%p,%@\\n",_weakMArr,_weakMArr);

NSLog(@"mArrOrigin中的數(shù)據(jù)引用計數(shù)%@", [mArrOrigin valueForKey:@"retainCount"]);

//修改原數(shù)組中的元素纲刀,看是否有隨之變化 copy也發(fā)生了改變

[mstr1appendFormat:@"aaa"];

NSLog(@"mArrOrigin輸出:%p,%@\\n", mArrOrigin,mArrOrigin);

NSLog(@"aCopyMArr輸出:%p,%@\\n",_aCopyMArr,_aCopyMArr);

NSLog(@"strongMArr輸出:%p,%@\\n",_strongMArr,_strongMArr);

NSLog(@"weakMArr輸出:%p,%@\\n",_weakMArr,_weakMArr);

#pragma mark ---- !!! 注意發(fā)現(xiàn)改變 mstr1

// _aCopyMArr 的第一個元素也發(fā)生了 也就是 copy 了array 但是沒有對每個元素

// 每個元素copy 一遍放新的數(shù)組里面去 注意是并沒有 這么做项炼。

}

如代碼中注意所說。

上面代碼有點多示绊,所做的操作是mArrOrigin(value1,value2)賦值給copy,strong,weak修飾的aCopyMArr,strongMArr,weakMArr锭部。通過給原數(shù)組增加元素,修改原數(shù)組元素值耻台,然后輸出mArrOrigin的引用計數(shù)空免,和數(shù)組地址,查看變化盆耽。

發(fā)現(xiàn)其中數(shù)組本身指向的內(nèi)存地址除了aCopyMArr重新開辟了一塊地址,strongMArr,weakMArr和mArrOrigin指針指向的地址是一樣的扼菠。也就是說

容器可變變量中容器本身和非容器可變變量是一樣的摄杂,copy深拷貝,strongMArr,weakMArr和assign都是淺拷貝

另外我們發(fā)現(xiàn)被拷貝對象mArrOrigin中的數(shù)據(jù)引用計數(shù)居然不是1而是3循榆。也就是說容器內(nèi)的數(shù)據(jù)拷貝都是進行了淺拷貝析恢。同時當(dāng)我們修改數(shù)組中的一個數(shù)據(jù)時strongMArr,weakMArr,aCopyMArr中的數(shù)據(jù)都改變了秧饮,說明

容器可變變量中的數(shù)據(jù)在拷貝的時候都是淺拷貝

第三 是非容器不可變變量 的修飾

- (void)nsstringTest

{

NSLog(@"\\n\\n\\n\\n------------------不可變量實驗------------------------");

NSString*strOrigin = [[NSStringalloc]initWithUTF8String:"strOrigin0123456"];

self.aCopyStr= strOrigin;

self.strongStr= strOrigin;

self.weakStr= strOrigin;

NSLog(@"strOrigin輸出:%p,%@\\n", strOrigin,strOrigin);

NSLog(@"aCopyStr輸出:%p,%@\\n",_aCopyStr,_aCopyStr);

NSLog(@"strongStr輸出:%p,%@\\n",_strongStr,_strongStr);

NSLog(@"weakStr輸出:%p,%@\\n",_weakStr,_weakStr);

NSLog(@"------------------修改原值后------------------------");

strOrigin =@"aaa";

NSLog(@"strOrigin輸出:%p,%@\\n", strOrigin,strOrigin);

NSLog(@"aCopyStr輸出:%p,%@\\n",_aCopyStr,_aCopyStr);

NSLog(@"strongStr輸出:%p,%@\\n",_strongStr,_strongStr);

NSLog(@"weakStr輸出:%p,%@\\n",_weakStr,_weakStr);

NSLog(@"------------------結(jié)論------------------------");

NSLog(@"strOrigin值值為改變映挂,但strOrigin和aCopyStr指針地址和指向都已經(jīng)改變,說明不可變類型值不可被修改盗尸,重新初始化");

self.aCopyStr=nil;

self.strongStr=nil;

NSLog(@"strOrigin輸出:%p,%@\\n", strOrigin,strOrigin);

NSLog(@"aCopyStr輸出:%p,%@\\n",_aCopyStr,_aCopyStr);

NSLog(@"strongStr輸出:%p,%@\\n",_strongStr,_strongStr);

NSLog(@"weakStr輸出:%p,%@\\n",_weakStr,_weakStr);

NSLog(@"------------------結(jié)論------------------------");

NSLog(@"當(dāng)只有weakStr擁有C時柑船,值依舊會被釋放,同非容器可變變量");

}

這個 weak 測試告訴我們 上面方法中 strong 和 copy strOrigin 影響了weak 這個屬性的值

對比 和 上面那個方法的測試 weakStr 的輸出泼各。

還有一個 strOrigin 被賦予新的值后前面一塊區(qū)域?qū)嶋H是被系統(tǒng)回收了 weak 的對象設(shè)置成了 null 值

這樣 沒有野指針鞍时。

- (void)weakStringTestTwo

{

NSString*strOrigin = [[NSStringalloc]initWithUTF8String:"HelloDeLong"];

self.weakStr= strOrigin;

NSLog(@"weakStr輸出:%p,%@\\n",_weakStr,_weakStr);

strOrigin =@"aaa";

NSLog(@"weakStr輸出:%p,%@\\n",_weakStr,_weakStr);

/*

weakStr輸出:0x6000002252a0,HelloDeLong\n

weakStr輸出:0x0,(null)\n

*/

}

第四 是 Block 類型的修飾

- (void)retainBlockAlone

{

// 前面已經(jīng)比較過strong 和 assign 的區(qū)別

TestBlockmBlock = ^(inta){

returna+3;

};

self.retainTestBlock= mBlock;

inta=self.retainTestBlock(4);

mBlock = ^(inta){

returna+5;

};

//self.retainTestBlock = mBlock;

intb=self.retainTestBlock(4);

mBlock =nil;

intc=self.retainTestBlock(4);// 無論 mBlock 如何改變都沒有改變 retainBlock

}


在處理用strong聲明的Block屬性引發(fā)的問題時偶然發(fā)現(xiàn)的。在諸多教程中都會講到:聲明屬性時用strong或者retain效果是一樣的(貌似更多開發(fā)者更傾向于用strong)。不過在聲明Block時逆巍,使用strong和retain會有截然不同的效果及塘。strong會等于copy,而retain竟然等于assign锐极!

當(dāng)然定義Block還是應(yīng)該用copy(還有其他需要注意的地方笙僚,可以參考這篇文章:iOS: ARC和非ARC下使用Block屬性的問題),因為非ARC下不copy的Block會在棧中灵再,ARC中的Block都會在堆上的肋层。?

代碼這東西 還是得敲 邊敲就會有新的靈感。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末檬嘀,一起剝皮案震驚了整個濱河市槽驶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鸳兽,老刑警劉巖掂铐,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異揍异,居然都是意外死亡全陨,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門衷掷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辱姨,“玉大人,你說我怎么就攤上這事戚嗅∮晏危” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵懦胞,是天一觀的道長替久。 經(jīng)常有香客問我,道長躏尉,這世上最難降的妖魔是什么蚯根? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮胀糜,結(jié)果婚禮上颅拦,老公的妹妹穿的比我還像新娘。我一直安慰自己教藻,他們只是感情好距帅,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著怖竭,像睡著了一般锥债。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天哮肚,我揣著相機與錄音登夫,去河邊找鬼。 笑死允趟,一個胖子當(dāng)著我的面吹牛恼策,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播潮剪,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼涣楷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了抗碰?” 一聲冷哼從身側(cè)響起狮斗,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弧蝇,沒想到半個月后碳褒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡看疗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年沙峻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片两芳。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡摔寨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出怖辆,到底是詐尸還是另有隱情是复,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布竖螃,位于F島的核電站佑笋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏斑鼻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一猎荠、第九天 我趴在偏房一處隱蔽的房頂上張望坚弱。 院中可真熱鬧,春花似錦关摇、人聲如沸荒叶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽些楣。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間愁茁,已是汗流浹背蚕钦。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鹅很,地道東北人嘶居。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像促煮,于是被迫代替她去往敵國和親邮屁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

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