前言
本文主要講的是NSString類有關的內(nèi)存管理基礎知識。
正文
一达罗、面試常問的問題:為什么NSString的修飾詞常常是copy
這個問題雖然網(wǎng)上已經(jīng)有很多了坝撑,但是大多數(shù)都是字面上的解釋:為了防止mutable string被無意中修改, NSMutableString是NSString的子類, 因此NSString指針可以持有NSMutableString對象静秆。
這樣說確實難理解,最好的方法還是用例子來解釋巡李。
創(chuàng)建一個繼承NSObject的類抚笔,添加一個屬性:
@interface Model : NSObject
@property (nonatomic, copy) NSString *name;
@end
再回到控制器中,初始化類等操作:
- (void)viewDidLoad
{
[super viewDidLoad];
Model *model = [Model new];
NSString *str = @"sss";
model.name = str;
NSLog(@"str = %@, name = %@", str, model.name);
}
如果你只是進行上述代碼的操作侨拦,那么copy殊橙,strong都無所謂。但是狱从,如果你要這樣:
- (void)viewDidLoad
{
[super viewDidLoad];
Model *model = [Model new];
NSMutableString *str = [[NSMutableString alloc] initWithString:@"sss"];
model.name = str;
[str appendString:@"aaa"];
NSLog(@"str = %@, name = %@", str, model.name);
}
你會發(fā)現(xiàn)就有問題了膨蛮。
當你的修飾詞是strong時,輸出如下:
2017-03-13 16:22:58.338 MRCTest[58598:2227863] str = sssaaa, name = sssaaa
當修飾詞是copy時:
2017-03-13 16:20:51.681 MRCTest[58501:2225726] str = sssaaa, name = sss
也就是季研,當你的修飾詞為strong時敞葛,你的name屬性很可能在你不知情的情況下被篡改。但是為什么一個會隨之改變一個不會呢与涡,往下看惹谐。
二、為什么修飾詞為copy的屬性不會隨著改變
還是例子來說明:
NSString *str = @"str";
NSString *strCopy = [str copy];
NSString *strMuCopy = [str mutableCopy];
NSLog(@"str = %p, \nstrCopy = %p, \nstrMuCopy = %p", str, strCopy, strMuCopy);
NSMutableString *muStr = [[NSMutableString alloc] initWithString:@"str"];
NSMutableString *muStrCopy = [muStr copy];
NSMutableString *muStrMuCopy = [muStr mutableCopy];
NSLog(@"muStr = %p, \nmuStrCopy = %p, \nmuStrMuCopy = %p", muStr, muStrCopy, muStrMuCopy);
輸出:
/*
str = 0x10d501108,
strCopy = 0x10d501108,
strMuCopy = 0x600000264f40
muStr = 0x608000266900,
muStrCopy = 0xa000000007274733,
muStrMuCopy = 0x608000264480
*/
從上面的例子可以看出:
1.當str不可變的時候驼卖,copy后地址不變(淺拷貝)氨肌,mutableCopy后地址改變(深拷貝)。
2.當str可變的時候款慨,不管copy或者mutableCopy都改變(深拷貝)儒飒。
地址一旦改變,也就意味著不會隨原來的str改變而改變了檩奠。
現(xiàn)在返回到第一大點:
如果給name賦值的屬性NSString桩了,也就是不可變的時候,copy為淺拷貝埠戳,所以和strong一樣井誉。
當給name賦值的屬性NSMutableString時候,如果是copy整胃,那么就會深拷貝颗圣,那么內(nèi)容不會隨之改變;如果是strong屁使,那么只是強引用在岂,地址仍然不變,所以會隨之改變了蛮寂。
另外蔽午,這里有需要注意的
實際上,不管是NSString或者NSMutableString酬蹋,只要調(diào)用copy及老,返回的都是NSString類型抽莱;相反,只要調(diào)用mutableCopy骄恶,返回的都是NSMutableString的食铐。
不信看這里:
NSMutableString *muStr = [[NSMutableString alloc] initWithString:@"str"];
NSMutableString *muStrCopy = [muStr copy];
[muStrCopy appendString:@"111"];
運行結果為奔潰,原因就是muStrCopy找不到appendString方法僧鲁,因為muStrCopy的類型是NSString虐呻。
三、NSString不同的創(chuàng)建方法悔捶,不同的引用計數(shù)
1:
NSString *stringConst = @"str";
該方法引用計數(shù)為-1或unsigned int 2147483647铃慷,因為他是字符串常量单芜。
2:
[stringConst retain];
對于字符串常量來說蜕该,retain和release都是沒有用的,所以引用計數(shù)仍然為-1洲鸠。
3:
NSString *string1 = [NSString stringWithFormat:@"hello"];
如果是這種創(chuàng)建方法堂淡,string1的引用計數(shù)為1。
4:
NSString *string2 = [NSString stringWithString:stringConst];
如果是這種創(chuàng)建方法扒腕,得具體看stringConst類型绢淀,如果是字符串常量,那么引用計數(shù)仍然為-1瘾腰。
5:
NSString *string2 = [NSString stringWithString:string1];
如果是這種創(chuàng)建方法皆的,得具體看string1類型,如果string1有引用蹋盆,那么引用計數(shù)為+1费薄。
所以這里的引用計數(shù)為2
四、不可變字符串對象一旦被創(chuàng)建栖雾,就不能修改它
在網(wǎng)上看到這句話楞抡,覺得很奇怪。明明可以修改拔雠骸U偻ⅰ!
其實這樣的账胧,這句話的意思是創(chuàng)建好后竞慢,那個地址上的內(nèi)容不能變了。但是你可以指向另一個地址啊治泥。例子:
代碼:
NSString *str = @"str1";
NSLog(@"%p", str);
str = @"str2";
NSLog(@"%p", str);
結果:
2017-03-13 17:02:21.722 MRCTest[59226:2251613] 0x103811118
2017-03-13 17:02:21.723 MRCTest[59226:2251613] 0x103811158
可以看出筹煮,str分別指向@"str1"和@"str2",但是地址不同车摄,說明了指向地址已經(jīng)改變啦寺谤。