上一篇文章基礎(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ù)組中的元素后忙厌,我們看到
arrayStrong
、arrayWeak
江咳、arrayCopy
內(nèi)部的元素都發(fā)生了變化逢净, - 這說明"容器可變變量
中的元素
"在拷貝過程中無論Copy
、Weak
歼指、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)
- 將
stringCopy
,stringStrong
設(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
掏秩。 -
Copy
、Strong
荆姆、Weak
蒙幻、Assign
都是淺拷貝都不會(huì)增加容器內(nèi)部元素的引用計(jì)數(shù)。
以下為全篇總結(jié):
Copy
胆筒、Strong
邮破、Assgin
诈豌、Weak
。
可變變量中:
-
Copy
會(huì)開辟一塊新的內(nèi)存抒和;而Strong
矫渔、Assgin
、Weak
不會(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
厦章、Assgin
、Weak
則和可變變量保持一致照藻。
容器:
容器本身遵守上面可變與不可變
的原則袜啃,只是內(nèi)部元素
只會(huì)被淺拷貝
。