OC 數組中的深拷貝與淺拷貝
淺拷貝:即指針拷貝,源對象和新對象指向的是同一個地址,也就是說淺拷貝要復出出來一個新的文件,但兩個文件的地址還是一個。淺拷貝的話是隻有不可變數組(如:NSArray,NSSet,NS字典)遇上copy,纔是淺拷貝,剩下的都是深拷貝。
Dog * dog1 = [Dog new];
// 這裏就是淺拷貝,即指針拷貝
Dog * dog2 = dog1;
深拷貝,自己定義的類一般需要遵循 NSCopying, NSMutableCopying 協議
Dog.h
@interface Dog : NSObject<NSCopying, NSMutableCopying>
@property (nonatomic) NSInteger age;
@end
Dog.m
@implementation Dog
- (id)copyWithZone:(NSZone *)zone
{
Dog * dog = [[self class] allocWithZone:zone];
dog.age = self.age;
return dog;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
Dog * dog = [[self class] allocWithZone:zone];
dog.age = self.age;
return dog;
}
- (NSString *) description {
return [NSString stringWithFormat:@"dog age: %ld", self.age];
}
@end
main.m
Dog * dog1 = [Dog new];
dog1.age = 5;
NSLog(@"dog1: %p, %@", dog1, dog1);
// mutableCopy 返回的是可變對象,自然可以設置對象的屬性值
Dog * dog2 = [dog1 mutableCopy];
dog2.age = 10;
// copy 返回的對象也可以設置對象的屬性值
// 所以,從這裏來看,其實自定義實現的 copy 和 mutableCopy 功能是一致的,都是返回可變對象的
Dog * dog2 = [dog1 copy];
dog2.age = 10;
NSLog(@"dog2: %p, %@", dog2, dog2);
OC 可變數組中的深拷貝與淺拷貝
所以,對數組進行深拷貝之後,其中對象的地址確實被重新創建。
NSMutableArray * arr1 = [NSMutableArray new];
for (int i = 0; i < 3; i++) {
Dog * dog = [Dog new];
[arr1 addObject:dog];
}
NSLog(@"arr1: %p, %@", arr1, arr1);
NSMutableArray * arr2 = [arr1 mutableCopy];
NSLog(@"arr2: %p, %@", arr2, arr2);
運行結果:
2017-010-10 10:55:39.895 深拷貝與淺拷貝[901:303] arr1: 0x1001089c0, (
"<Dog: 0x100108430>",
"<Dog: 0x100109fc0>",
"<Dog: 0x100109fd0>"
)
2017-10-10 10:55:39.917 深拷貝與淺拷貝[901:303] arr2: 0x100301ad0, (
"<Dog: 0x100108430>",
"<Dog: 0x100109fc0>",
"<Dog: 0x100109fd0>"
)
因爲 “數組中只是存儲了對象的地址,而非存儲了對象的本體。”所以,Dog 對象的空間並沒有被複制。
因此,可變數組的 “深拷貝”並沒有將其中所有元素都複製,其中的對象元素只進行了淺複製!
解決方法:重新將所有對象都拷貝一份
NSMutableArray * arr2 = [NSMutableArray new];
for (int i = 0; i < arr1.count; i++) {
Dog * newDog = [arr1[i] copy];
[arr2 addObject:newDog];
}
NSLog(@"arr2: %p, %@", arr2, arr2);
OC中對於數組的深拷貝,不能想當然地認爲,已經將其中元素空間都拷貝了。實際上,其中的元素只是淺拷貝而已!
如果需要實現深拷貝的話,可以通過一個一個元素進行深拷貝,重新添加到可變數組中!
COPY 返回一個不可變對象的副本,MutalbeCopy返回一個可變對象的副本。
NSArray *array=[NSArray arrayWithObjects:@"one",@"two", nil];
NSMutableArray *array1=[array copy];
[array1 addObject:@"three"]; //error
NSMutableArray *array2=[array mutableCopy];
[array2 addObject:@"three"]; //right
// insert code here...
NSLog(@"Hello, World!");
比較與區別
複製對象的基本概念:複製一個對象爲副本,開闢一塊新的內存來存儲副本對象。
如果一個對象想具備複製的功能,必須實現協議和協議
NSObject自帶的常用的對象有:NSNumber、NSString、NSArray、NSDictionary、NSMutableArray、NSMutableDictionay、NSMutableString,copy產生的對象時不可變的,mutableCopy產生的對象時可變的
COPY和MutableCopy的區別
COPY 返回一個不可變對象的副本,MutalbeCopy返回一個可變對象的副本。
淺copy和深copy
淺複製盡複製對象本身,對象裏的屬性、包含的對象不做複製。
淺複製只是複製指針,並沒有創建新的內存空間。
深複製複製全部,包括對象的屬性和其他對象
Foundation框架支持複製的類,默認是淺複製
對象的自定義拷貝
對象擁有複製特性,必須實現NSCopying,NSMutableCopying協議,實現該協議的copyWithZone方法和mutableCopyWithZone方法
深拷貝和淺拷貝的區別就在於copyWithZone方法的實現,
copy、mutableCopy和retain之間的關係
在Foundation對象中,copy是一個不可變的對象時,作用相當於retain
當使用mutableCopy時,不管源對象是否可變,副本是可變的,並且實現真正意義上的copy
當我們使用copy一個可變對象時,副本對象是不可變的。
NSFoundation,當我們copy的時一個不可變對象時,默認的copy都是淺拷貝,相當於retain
當使用mutableCopy時,不管對象是否可變,都會實現深拷貝
retain相當於兩個對象指向同一個指針