iOS 深度理解淺拷貝與深拷貝
在工作中如果不能正確理解淺拷貝與深拷貝就會造成不想改變的值被改變了,出現了再次使用陣列時沒有資料,顯示的值不是我們想要的等一些問題。只有真正理解了淺拷貝與深拷貝才能使我們在開發中事半功倍,廢話少說,程式碼走起~~~
定義理解
淺拷貝:拷貝後只是指向了該物件的地址,這兩個物件指向了同一個記憶體地址,通過任何一個物件修改值,這兩個物件再次獲取值都是獲取修改後的值。
深拷貝:拷貝了物件的內容然後重新開闢了新的記憶體空間,這是兩個互相獨立的物件,對任意一個修改值,另一個的值都不會改變。
字串的深拷貝與淺拷貝
不可變字串
NSString *test = @"copy456" ;
NSString *test1 = [test copy]; //淺拷貝
NSString *test2 = [test mutableCopy]; //深拷貝
列印結果:
test:0x101683068
test1:0x101683068
test2:0x604000049330
從列印結果我們可以看到使用copy賦值給一個不可變物件時是淺拷貝,指向了同一個記憶體地址。使用mutableCopy賦值給一個不可變物件是深拷貝,重新分配了記憶體空間。
可變字串
NSMutableString *mtest = [[NSMutableString alloc] initWithString:@"mutableCopy NSSting" ];
NSMutableString *mtest4 = [mtest copy]; // 深拷貝
NSMutableString *mtest5 = [mtest mutableCopy]; //深拷貝
列印結果:
mtest:0x600000445ac0
mtest4:0x600000445c10
mtest5:0x600000445a90
通過copy或mutableCopy的方式賦值給可變物件,從列印的結果可以看到它們三個指向的記憶體地址都是不一樣的,因此都是深拷貝。
集合類物件的深拷貝與淺拷貝
對於集合類物件我們以陣列為例進行說明
不可變物件
NSArray *testArray = @[@"A" , @"B", @"C"];
NSArray *testArray1 = [testArray copy]; //淺拷貝
NSArray *testArray2 = [testArray mutableCopy]; //深拷貝
列印結果:
testArray:0x60400004a4d0
testArray1:0x60400004a4d0
testArray2:0x60400004a770
通過copy賦值testArray1與testArray指向相同的記憶體地址,因此通過copy的方式賦值給不可變物件是淺拷貝。testArray2是新的記憶體地址,通過mutableCopy的方式賦值給一個不可變物件是深拷貝。
可變物件
NSMutableArray *mTestArray = [[NSMutableArray alloc] init];
NSMutableArray *mTestArray1 = [mTestArray copy]; //深拷貝
NSMutableArray *mTestArray2 = [mTestArray mutableCopy]; //淺拷貝
列印結果:
testArray:0x60800005ba50
testArray1:0x60c000004910
testArray2:0x60800005bc00
無論是copy還是mutableCopy賦值給一個可變物件時都是深拷貝。
集合物件的值
列印陣列的第一個值的記憶體地址
NSLog(@"testArray 1value:%p", [mTestArray objectAtIndex:0]);
NSLog(@"testArray1 1value:%p", [mTestArray1 objectAtIndex:0]);
NSLog(@"testArray2 1value:%p", [mTestArray2 objectAtIndex:0]);
列印結果:
testArray 1value:0x104b67238
testArray1 1value:0x104b67238
testArray2 1value:0x104b67238
我們看到列印的結果第一個值都指向了同一個記憶體地址,這說明集合物件的深拷貝只是單層深拷貝,只是給該物件分配了一個新的記憶體地址而集合物件裡面的值還都指向原來的記憶體地址。
property中使用copy屬性
@interface ViewController ()
@property (nonatomic, copy) NSString *pTest;
@property (nonatomic, copy) NSMutableString *mpTest;
@end
self.pTest = test;
NSLog(@"test:%p", test);
NSLog(@"pTest:%p", _pTest);
self.mpTest = mtest;
NSLog(@"mtest:%p", mtest);
NSLog(@"mpTest:%p", _mpTest);
列印結果:
test:0x10b07e088
pTest:0x10b07e088
mtest:0x6040002410e0
mpTest:0x604000241770
通過列印結果我們可以看到不可變物件是淺拷貝,可變度物件是深拷貝。其實看到set方法的實現原來我們就明白了property裡的copy什麼時候是深拷貝,什麼時候是淺拷貝
- (void)setPTest:(NSString *)pTest {
_pTest = [pTest copy];
}