iOS中的深復制與淺復制


很多語言中都有深復制淺復制的概念,如C++,ObjC等。簡單來說,淺復制就是兩個變量指向了同一塊內存區域,深復制就是兩個變量指向了不同的內存區域,但是兩個內存區域里面的內容是一樣的。

淺復制示意圖:

 

深復制示意圖:

iOS開發中,淺復制和深復制要更復雜一些,涉及到集合對象和非集合對象的copy與mutableCopy。

非集合對象:如NSString,NSInteger,NSNumber……

集合對象:如NSArray,NSDictionary,……

1:非集合對象的copy與mutableCopy。

非集合對象的copy與mutableCopy,只需要遵循以下規則即可:

  (1)可變對象的copy和mutableCopy方法都是深復制

  (2)不可變對象的copy方法是淺復制,mutableCopy方法是深復制

  (3)copy方法返回的對象是不可變對象

下面通過代碼來驗證:

可變對象的copy與 mutableCopy方法:

void testMutable()
{
    //可變對象的復制,copy和mutableCopy都是深拷貝
    NSMutableString *str1 = [NSMutableString stringWithString:@"test"];
    NSMutableString *str2 = [str1 copy];
    //copy返回的是不可變對象,因此str2不能改變,會發生崩潰
    //[str2 appendString:@"test"];
    NSMutableString *str3 = [str1 mutableCopy];
    [str3 appendString:@"test"];
    NSLog(@"%@ %@ %@",str1,str2,str3);
    NSLog(@"%p %p %p",str1,str2,str3);
}

執行結果:

可以看到,三個字符串的地址是不相同的,說明copy和 mutableCopy方法都是深復制。

不可變對象的copy與mutableCopy方法:

void testNoMutable() { NSString *str1 = @"test"; //直接copy是淺復制
    NSMutableString *str2 = [str1 copy]; //copy返回的是不可變對象,str2不能被修改,因此會發生崩潰 //[str2 appendString:@"test"]; //mutableCopy是深復制
    NSMutableString *str3 = [str1 mutableCopy]; [str3 appendString:@"test"]; NSLog(@"%@ %@ %@",str1,str2,str3); NSLog(@"%p %p %p",str1,str2,str3); }

執行結果:

可以看到:前兩個地址一樣,第三個地址不一樣,因此不可變對象的copy方法是淺復制,mutableCopy方法是深復制。

另外需要注意:無論是可變對象還是不可變對象,copy 方法返回的對象都是不可變的。

2:集合對象的copy與mutableCopy

實際上,集合對象與非集合對象所遵循的規則基本上是一樣的。

可變對象的的copy與mutableCopy 方法

驗證代碼:

void testSetMutable()
{
    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
    //可變對象copy是深復制
    NSMutableArray *array2 = [array1 copy];
    //copy返回的是不可變對象,array2不能被修改,因此會崩潰
    //[array2 addObject:@"d"];
    //可變對象的mutableCopy是深復制
    NSMutableArray *array3 = [array1 mutableCopy];
    [array3 addObject:@"d"];
    NSLog(@"%p %p %p",array1,array2,array3);
}

執行結果:

可以看到地址是不一樣的。說明可變對象的copy和mutableCopy方法都是深復制。

不可變對象的copy與mutableCopy方法

驗證代碼:

void testSetNoMutable()
{
    NSArray *array1 = @[@"a",@"b",@"c"];
    //不可變對象的copy方法,淺復制
    NSArray *array2 = [array1 copy];
    //不可變對象的mutableCopy方法,深復制
    NSArray *array3 = [array1 mutableCopy];
    NSLog(@"%p %p %p",array1,array2,array3);
}

執行結果:

可以看到,前兩個地址一樣,第三個地址不一樣。說明不可變對象的copy方法是淺復制,mutableCopy方法是深復制。

集合對象和非集合對象的一個差別:

上面說的集合對象的深復制並不是嚴格意義上的深復制,而是單層深復制。

單層深復制:對集合對象來說,深復制時只是將第一層對象進行了深復制,內部的對象仍然是淺復制。比如說

NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];

調用copy方法   NSArray *array2 = [array1 copy] ,有分配了一塊內存,array2指向了這塊內存,但是數組內部的元素,指向的仍然是數組1內部的元素,即內部元素是淺復制。

驗證代碼:

void testSetMutable()
{
    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
    //可變對象copy是深復制
    NSMutableArray *array2 = [array1 copy];
    //copy返回的是不可變對象,array2不能被修改,因此會崩潰
    //[array2 addObject:@"d"];
    //可變對象的mutableCopy是深復制
    NSMutableArray *array3 = [array1 mutableCopy];
    [array3 addObject:@"d"];
    NSLog(@"%p %p %p",array1,array2,array3);
    NSLog(@"%p %p %p",array1[0],array2[0],array3[0]);
}

執行結果:

可以看到,三個數組的第一個元素的地址是一樣的,也就是說內部元素是淺復制。

3:集合對象的完全復制

集合對象的完全復制,就是集合中的每一層的元素都是深復制。

方法一:

使用 initWith***: copyItems:YES  方法。

代碼:

void testFullCopy()
{
    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
    NSArray *array2 = [[NSArray alloc] initWithArray:array1 copyItems:YES];
    NSLog(@"%p %p",array1,array2);
    NSLog(@"%p %p",array1[0],array2[0]);
}

執行結果:

可以看到數組元素的地址不一樣。

方法二:

先將集合進行歸檔,然后再解檔。代碼如下:

void testFullCopy2()
{
    NSMutableArray *array1 = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c", nil];
    NSArray *array2 = [NSKeyedUnarchiver unarchiveTopLevelObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:array1 ] error:nil];
    NSLog(@"%p %p",array1,array2);
    NSLog(@"%p %p",array1[0],array2[0]);
}

執行結果:

可以看到數組元素的地址不一樣。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM