這個(gè)問題其實(shí)很簡單, 但比較容易讓人忽略.
解釋這個(gè)問題前, 首先要明白, NSString屬性為什么要用copy來修飾?
NSString屬性之所有用copy來修飾, 是為了防止不同的指針變量指向同一個(gè)內(nèi)存地址, 從而形成連帶效應(yīng)----就是改變一個(gè)變量的值, 另一個(gè)值也隨之發(fā)生改變.比如:
@interface Demo()@property (strong, nonatomic)
NSString *S;
@end
@implementation
NSMutableString *MS = [[NSMutableString alloc] initWithString:@"ABC"];
_S = MS;
@end
這段代碼里, 如果NSString屬性不用copy而用strong修飾的話, 就會(huì)造成兩個(gè)指針變量同時(shí)指向同一塊存儲空間的問題.具體原因如圖:
代碼中的"ABC"是存放在堆中的. 因?yàn)镹SMutableString的initWithSring方法會(huì)將傳入的參數(shù)從常量區(qū)中拷貝一份, 放入堆中.
這種情況下, 由于NSMutableString的特點(diǎn)就是只會(huì)對同一塊內(nèi)存進(jìn)行操作, 所以不管是改變可變字符串"MS"的值, 還是改變實(shí)例對象"S"的值, 另一個(gè)對象的值也都會(huì)隨之發(fā)生改變. 這樣代碼的管理就會(huì)非常混亂.
而如果用copy修飾的話, 在賦值的時(shí)候, 編譯器會(huì)在setter方法中進(jìn)行判斷: 如果等號左邊是一個(gè)可變字符串, 就讓等號左邊的指針變量指向一個(gè)copy出來的新地址, 這樣就可以解決上面的問題.
如圖:
那么, 為什么開發(fā)中NSString屬性可以用strong呢?
因?yàn)閷?shí)際開發(fā)中, 幾乎用不到NSMutableString啊!!!
我們都是用一個(gè)NSString給另一個(gè)NSString賦值啊!!!
比如:
@interface Demo()@property (strong, nonatomic)
NSString *S;
@end
@implementation
NSString *MS = @"ABC";
_S = MS;
@end
這樣的話, 在內(nèi)存中就變成了:
這樣看似兩個(gè)指針變量又都指向了同一塊內(nèi)存, 但因?yàn)橹赶虻氖浅A繀^(qū), 而常量區(qū)的內(nèi)容是不可改變的, 所以即使任何一方改變了指針指向中的內(nèi)容, 編譯器都會(huì)重新在常量區(qū)中開辟一塊空間來保存新的內(nèi)容, 然后改變該指針的指向, 讓它重新指向新的內(nèi)容.
比如
@implementation
NSString *MS = @"ABC";
_S = MS;
MS = @"EFG"
@end
內(nèi)存示意圖如下:
正是因?yàn)檫@樣, 我們才可以在開發(fā)中將NSString屬性的策略定義成strong.
那么用strong修飾NSString的意義何在呢?
前面提到過, 如果你用copy修飾了NSString, 那么編譯器會(huì)在setter方法里進(jìn)行判斷參數(shù)和對象是可變還是不可變, 判斷當(dāng)然要消耗性能, 想想一個(gè)項(xiàng)目里有多少個(gè)字符串, 每一個(gè)字符串都消耗一點(diǎn)點(diǎn)性能, 那么多字符串加起來消耗的性能也是比較多的, 所以如果用strong來修飾, 可以在一定程度上減少一點(diǎn)無謂性能犧牲.(這也是我在開發(fā)中訪問屬性一直用"_"而不是"self."的原因)
當(dāng)然, 如果用strong修飾了NSString屬性的話, 必須要確保的就是將來給這個(gè)屬性賦值時(shí), 用的同樣是NSString, 而不是NSMutableString