iOS理解“對象等同性”這一概念

前言

最近看了一道題
NSString *s1 = @"Hello world"; NSString *s2 = @"Hello world";請問 s1 == s2的返回值是YES還是NO腹暖?,
相信很多童鞋的答案都是NO,可能大家認(rèn)為s1愿阐、s2兩個對象的地址不同微服,但是事實(shí)真的如此么?

為此特意寫了一個demo來印證下:


#importint main(int argc, const char * argv[]) {

@autoreleasepool {

NSString *str1 = @"abc";

NSString *str2 = [NSString stringWithFormat:@"%@",@"abc"];

NSString *str3 = [[NSString alloc]initWithString:str1];

NSString *str4 = [NSString stringWithString:str1];

NSString *str8 = [[NSString alloc] initWithString:@"abc"];

NSString *str9 = [NSString stringWithString:@"abc"];

NSString *str5 = [str1 copy];

NSString *str6 = [str1 mutableCopy];

NSString *str7 = [NSString stringWithFormat:@"%@",@"abc"];

NSLog(@"str1: %p",str1);

NSLog(@"str2: %p",str2);

NSLog(@"str3: %p",str3);

NSLog(@"str4: %p",str4);

NSLog(@"str5: %p",str5);

NSLog(@"str6: %p",str6);

NSLog(@"str7: %p",str7);

NSLog(@"str8: %p",str8);

NSLog(@"str9: %p",str9);

NSLog(@"===============");

NSLog(@"str1 == str2  \t\t%@",(str1 == str2) ? @"YES" : @"NO");

NSLog(@"str1 Equal str2  \t%@",[str1 isEqualToString:str2] ? @"YES" : @"NO");

NSLog(@"str1 == str3  \t\t%@",(str1 == str3) ? @"YES" : @"NO");

NSLog(@"str1 == str4  \t\t%@",(str1 == str4) ? @"YES" : @"NO");

NSLog(@"str3 == str4  \t\t%@",(str4 == str3) ? @"YES" : @"NO");

NSLog(@"str2 == str6  \t\t%@",(str2 == str6) ? @"YES" : @"NO");

NSLog(@"str2 Equal str6  \t%@",[str2 isEqualToString:str6] ? @"YES" : @"NO");

NSLog(@"str2 == str7  \t\t%@",(str7 == str2) ? @"YES" : @"NO");

NSLog(@"%d",str2 == str7);

}

return 0;

}

//LOGCAT如下

2017-02-28 13:27:45.326 testEqual[6456:440040] str1: 0x100001048

2017-02-28 13:27:46.022 testEqual[6456:440040] str2: 0x63626135

2017-02-28 13:27:46.765 testEqual[6456:440040] str3: 0x100001048

2017-02-28 13:27:47.284 testEqual[6456:440040] str4: 0x100001048

2017-02-28 13:27:47.732 testEqual[6456:440040] str5: 0x100001048

2017-02-28 13:27:48.835 testEqual[6456:440040] str6: 0x100102370

2017-02-28 13:27:49.690 testEqual[6456:440040] str7: 0x63626135

2017-02-28 13:28:05.204 testEqual[6456:440040] str8: 0x100001048

2017-02-28 13:28:16.683 testEqual[6456:440040] str9: 0x100001048

2017-02-28 13:29:17.041 testEqual[6456:440040] ===============

2017-02-28 13:29:18.178 testEqual[6456:440040] str1 == str2  NO

2017-02-28 13:29:21.152 testEqual[6456:440040] str1 Equal str2  YES

2017-02-28 13:31:01.274 testEqual[6456:440040] str1 == str3  YES

2017-02-28 13:31:01.274 testEqual[6456:440040] str1 == str4  YES

2017-02-28 13:31:02.918 testEqual[6456:440040] str3 == str4  YES

2017-02-28 13:31:02.918 testEqual[6456:440040] str2 == str6  NO

2017-02-28 13:31:02.918 testEqual[6456:440040] str2 Equal str6  YES

2017-02-28 13:31:02.918 testEqual[6456:440040] str2 == str7  YES

2017-02-28 13:31:02.919 testEqual[6456:440040] 1

由此可以得出結(jié)論

Tips:

  1. str1 是 直接使用字面量語法賦值的變量缨历。所以以蕴,跟str8,str9是一樣的,編譯器都會執(zhí)行同樣的代碼來生成對象辛孵。

  2. str3和str4,則都是根據(jù)一個已知的字符串變量來生成對象丛肮。其實(shí)就是比上面Tip1多了一個步驟、所以魄缚,str3和str8宝与,str4和str9地址是相同的

  3. str2和str7[NSString stringWithFormat:@"%@",@"abc"]都是格式化生成,地址也是相同的

擴(kuò)展:NSString *str10 = [NSString stringWithFormat:@"%@",str1];同理冶匹,如果新加一個str10习劫,那它的地址應(yīng)該跟str2,str7也是一樣的

  1. str5[str1 copy]和str6[str1 mutableCopy]

這兩個涉及到深淺拷貝,

str5是str1的淺拷貝嚼隘,指針都指向相同的地址

str6是str1的深拷貝诽里,等于重新創(chuàng)建了一個新的對象所以地址是不同的

因此

如果上面的問題換種問法,比如:

`NSString *s1 = @"hello";

NSString *s2 = [[NSString alloc] initWithString:s1];

請問s1==s2的返回值飞蛹?`

或者

`NSString *s1 = [NSString stringWithFormat:@"hello"];

NSString *s2 = [NSString stringWithFormat:@"hello"];

請問s1==s2的返回值谤狡?`

答案也都是YES!

PS:

單說NSString,系統(tǒng)為我們提供了一個isEqualToString:方法卧檐,所以一般情況下來說墓懂,我們是不會使用==來判斷兩個NSString對象是否相等的。

==isEqualToString:有什么區(qū)別呢霉囚?

由上面的例子也可以看到捕仔,

`str1 == str2 NO

str1 Equal str2 YES`

isEqualToString:應(yīng)該是只比較了兩個對象的值,不比較地址

==則會比較兩個對象的地址和值是否都相等

畢竟判斷兩個對象是否相等的條件是:

當(dāng)且僅當(dāng)其“指針值(pointer value)”完全相等時盈罐,這兩個對象才相等.


2018年11月26日延伸:

一逻澳、NSString對象copystrong修飾詞的區(qū)別

//先聲明兩個變量
@property (nonatomic, strong) NSString *strongStr;
@property (nonatomic, copy) NSString *cpyStr;

然后這里分兩種情況

  1. 不可變str的情況
- (void)inmutableTest {
    NSString *string = [NSString stringWithFormat:@"abc"];
    self.strongStr = string;
    self.cpyStr = string;
    NSLog(@"string:%@, 對象地址:%p, 指針地址:%p", string,string,&string);
    NSLog(@"strongStr:%@, 對象地址:%p, 指針地址:%p,", self.strongStr,_strongStr,&_strongStr);
    NSLog(@"cpyStr:%@, 對象地址:%p, 指針地址:%p", self.cpyStr,_cpyStr,&_cpyStr);
    
    //改變string的值
    string = @"123";
    
    NSLog(@"string:%@, 對象地址:%p, 指針地址:%p", string,string,&string);
    NSLog(@"strongStr:%@, 對象地址:%p, 指針地址:%p,", self.strongStr,_strongStr,&_strongStr);
    NSLog(@"cpyStr:%@, 對象地址:%p, 指針地址:%p", self.cpyStr,_cpyStr,&_cpyStr);
}
//結(jié)果:
//string:abc, 對象地址:0xe9f9b161ce4bbd88, 指針地址:0x7ffee1306e48
//strongStr:abc, 對象地址:0xe9f9b161ce4bbd88, 指針地址:0x7fcc7b42a660,
//cpyStr:abc, 對象地址:0xe9f9b161ce4bbd88, 指針地址:0x7fcc7b42a668
//string:123, 對象地址:0x10e8fa1a0, 指針地址:0x7ffee1306e48
//strongStr:abc, 對象地址:0xe9f9b161ce4bbd88, 指針地址:0x7fcc7b42a660,
//cpyStr:abc, 對象地址:0xe9f9b161ce4bbd88, 指針地址:0x7fcc7b42a668

可以看到,在string為NSString(不可變)的情況下暖呕,修改string的值意味著改變指針的指向
此時斜做,copystrong修飾的新字符串值都不會變!因?yàn)樗麄兊闹羔樦赶虻牡刂范歼€是以前的地址M謇俊瓤逼!

  1. 可變Str的情況
- (void)mutableTest {
    NSMutableString *string= [[NSMutableString alloc]initWithString:@"abc"];
    self.strongStr = string;
    self.cpyStr = string;
    NSLog(@"string:%@, 對象地址:%p, 指針地址:%p", string,string,&string);
    NSLog(@"strongStr:%@, 對象地址:%p, 指針地址:%p,", self.strongStr,_strongStr,&_strongStr);
    NSLog(@"cpyStr:%@, 對象地址:%p, 指針地址:%p", self.cpyStr,_cpyStr,&_cpyStr);
    
    //改變string的值
    [string appendFormat:@"%@",@"123"];
    
    NSLog(@"string:%@, 對象地址:%p, 指針地址:%p", string,string,&string);
    NSLog(@"strongStr:%@, 對象地址:%p, 指針地址:%p,", self.strongStr,_strongStr,&_strongStr);
    NSLog(@"cpyStr:%@, 對象地址:%p, 指針地址:%p", self.cpyStr,_cpyStr,&_cpyStr);
}
//結(jié)果:
//string:abc, 對象地址:0x60000094ffc0, 指針地址:0x7ffee2898758
//strongStr:abc, 對象地址:0x60000094ffc0, 指針地址:0x7f998c70d520,
//cpyStr:abc, 對象地址:0x9b661481bbd71a70, 指針地址:0x7f998c70d528
//string:abc123, 對象地址:0x60000094ffc0, 指針地址:0x7ffee2898758
//strongStr:abc123, 對象地址:0x60000094ffc0, 指針地址:0x7f998c70d520,
//cpyStr:abc, 對象地址:0x9b661481bbd71a70, 指針地址:0x7f998c70d528

此結(jié)果就能明顯看到區(qū)別了笼吟,
strong修飾的字符串,會跟隨源字符串的變化而變化霸旗!copy修飾的并不會4铩!

這也可以解釋:為什么NSString的變量要用copy來修飾
生成NSString對象的時候诱告,就是不想在后續(xù)的過程中改變他撵枢,如果使用strong來修飾,則途中修改了原值精居,strong修飾的變量也會跟著變化锄禽,這顯然有悖于初衷

二、有關(guān)原文中stringWithFormat生成對象地址和別的方法生成對象地址不同的問題:

由上文可以看到靴姿,stringWithFormatinitWithFormat兩方法生成的NSString對象地址是相同的沃但。其他的任何方法生成的對象都不同!因?yàn)?code>stringWithFormat方法內(nèi)部也是調(diào)用了initWithFormat方法佛吓。


原因是這樣:
stringWithFormat方法會創(chuàng)建一個新的對象宵晚,開辟新的內(nèi)存空間,遵循引用計數(shù)原則维雇,創(chuàng)建釋放等等淤刃。
stringWithString等方法,其實(shí)并沒有創(chuàng)建一個新的對象吱型,蘋果對于這種字面量字符串逸贾,一般都是存儲在常量區(qū)stringWithFormat等方法只是添加一個該常量的引用而已唁影,并不會開辟新的內(nèi)存空間

這也就能解釋為什么這兩種方式創(chuàng)建的字符串,內(nèi)存地址不同了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掂名,一起剝皮案震驚了整個濱河市据沈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饺蔑,老刑警劉巖锌介,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異猾警,居然都是意外死亡孔祸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門发皿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來崔慧,“玉大人,你說我怎么就攤上這事穴墅』淌遥” “怎么了温自?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長皇钞。 經(jīng)常有香客問我悼泌,道長,這世上最難降的妖魔是什么夹界? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任馆里,我火速辦了婚禮,結(jié)果婚禮上可柿,老公的妹妹穿的比我還像新娘鸠踪。我一直安慰自己,他們只是感情好趾痘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布慢哈。 她就那樣靜靜地躺著,像睡著了一般永票。 火紅的嫁衣襯著肌膚如雪卵贱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天侣集,我揣著相機(jī)與錄音键俱,去河邊找鬼。 笑死世分,一個胖子當(dāng)著我的面吹牛编振,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播臭埋,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼踪央,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瓢阴?” 一聲冷哼從身側(cè)響起畅蹂,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荣恐,沒想到半個月后液斜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叠穆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年少漆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片硼被。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡示损,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嚷硫,到底是詐尸還是另有隱情屎媳,我是刑警寧澤夺溢,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站烛谊,受9級特大地震影響风响,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丹禀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一状勤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧双泪,春花似錦持搜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至村斟,卻和暖如春贫导,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蟆盹。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工孩灯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逾滥。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓峰档,卻偏偏與公主長得像,于是被迫代替她去往敵國和親寨昙。 傳聞我的和親對象是個殘疾皇子讥巡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

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

  • NSRange : 表示范圍作用的結(jié)構(gòu)體,3種方式創(chuàng)建 // 方式一 NSRange range; locatio...
    路墨閱讀 1,013評論 1 8
  • java筆記第一天 == 和 equals ==比較的比較的是兩個變量的值是否相等舔哪,對于引用型變量表示的是兩個變量...
    jmychou閱讀 1,497評論 0 3
  • 1欢顷、禁止手機(jī)睡眠[UIApplication sharedApplication].idleTimerDisabl...
    DingGa閱讀 1,117評論 1 6
  • 我想可能很多人在戀愛中都像我一樣:一牽手就在心中規(guī)劃好了一生外里。 在戀愛中總是會問對方,你想過我們要有以后嗎特石?以前曾...
    輕情閱讀 319評論 0 0
  • liunx命令總共常用只有80個盅蝗,總共600個 liunx和DOS,window不同是姆蘸,只要文件有可執(zhí)行權(quán)限墩莫,不管...
    stillriver閱讀 429評論 0 0