iOS 浅拷贝和深拷贝

322 阅读4分钟

一: 定义

浅拷贝: 浅拷贝并不拷贝对象本身, 只是拷贝指向对象的指针, 将指针指向新的对象;
深拷贝: 直接拷贝对象到内存中的一块区域, 然后把新对象的指针指向这块内存;

补充:

在iOS中并不是所有对象都支持Copy和MutableCopy;  
遵循NSCopying协议的类可以发送Copy协议;  
遵循NSMutableCopying协议的类可以发送MutableCopy消息.
如果一个对象没有遵循这两个协议而发送Copy或者MutableCopy消息,那么会发生异常.    
如果要遵循NSCopying协议, 那么必须实现copyWithZone方法.
如果要遵循NSMutableCopying协议, 那么必须实现mutableCopyWithZone方法;

二: copy 和 mutableCopy

1: 非容器对象(比如: NSString)

1.1 非容器不可变对象调用Copy和MutableCopy; 如NSString

//不可变字符串的内存地址和指针地址
NSString *test = @"test";
NSLog(@"test = %p",test);
NSLog(@"&test = %p",&test);
   
//不可变字符串copy后的内存地址和指针地址
NSString *test1 = test.copy;
NSLog(@"test1 = %p",test1);
NSLog(@"&test1 = %p",&test1);

//不可变字符串mutableCopy后的内存地址和指针地址
id test2 = test.mutableCopy;
NSLog(@"[test2 class] = %@",[test2 class]);
NSLog(@"test2 = %p",test2);
NSLog(@"&test2 = %p", &test2);

输出结果:
test = 0x109869290
&test = 0x7ffee65ff738

test1 = 0x109869290
&test1 = 0x7ffee65ff740

[test2 class] = __NSCFString
test2 = 0x600003f34840
&test2 = 0x7ffee65ff748

从输出结果可以看出:
(1)非容器不可变对象调用copy方法, 其实只是把当前对象的指针指向了原对象的地址;
(2)调用mutableCopy方法, 则是新分配了一块内存区域, 并把新对象的指针指向了这块区域;

1.2 非容器可变对象调用copy 和 mutableCopy, 如: NSMutableString

//非容器可变字符串的内存地址和指针地址
NSMutableString *mTest1 = [[NSMutableString alloc] initWithString:@"mTest1"];
NSLog(@"mTest1 = %p",mTest1);
NSLog(@"&mTest1 = %p",&mTest1);
  
//非容器可变字符串copy后的内存地址和指针地址 
id mTest1Copy = mTest1.copy;
NSLog(@"[mTest1Copy class] = %@",[mTest1Copy class]);
NSLog(@"mTest1Copy = %p",mTest1Copy);
NSLog(@"&mTest1Copy = %p", &mTest1Copy);
    
//非容器可变字符串mutableCopy后的内存地址和指针地址
id mTest1MutableCopy = mTest1.mutableCopy;
NSLog(@"[mTest1MutableCopy class] = %@",[mTest1MutableCopy class]);
NSLog(@"mTest1MutableCopy = %p",mTest1MutableCopy );
NSLog(@"&mTest1MutableCopy = %p",&mTest1MutableCopy);

输出结果:
mTest1 = 0x600002d84e40
&mTest1 = 0x7ffee9ee0750

[mTest1Copy class] = NSTaggedPointerString
mTest1Copy = 0xdcf5175d7b253fbc
&mTest1Copy = 0x7ffee9ee0758

[mTest1MutableCopy class] = __NSCFString
mTest1MutableCopy = 0x600002d800f0
&mTest1MutableCopy = 0x7ffee9ee0760

从输出结果可以看出:
非容器可变对象调用copy和mutableCopy方法后都会重新分配一块内存区域.

2: 容器对象(比如: NSArray)

2.1 不可变容器对象调用Copy和MutableCopy; 如NSArray

//不可变数组的内存地址和指针地址
NSArray *testArray = @[@"1", @"2", @"3"];
NSLog(@"testArray = %p",testArray);
NSLog(@"&testArray = %p", &testArray);
    
//不可变数组copy后的内存地址和指针地址
NSArray *testArrayCopy = testArray.copy;
NSLog(@"[testArrayCopy class] = %@",[testArrayCopy class]);
NSLog(@"testArrayCopy = %p",testArrayCopy);
NSLog(@"&testArrayCopy = %p",&testArrayCopy);

//不可变数组mutableCopy后的内存地址和指针地址
id testArrayMutableCopy = testArray.mutableCopy;
NSLog(@"[testArrayMutableCopy class] = %@",[testArrayMutableCopy class]);
NSLog(@"testArrayMutableCopy = %p",testArrayMutableCopy);
NSLog(@"&testArrayMutableCopy = %p",&testArrayMutableCopy);

输出结果:
testArray = 0x600001780a50
&testArray = 0x7ffeee00e730

[testArrayCopy class] = __NSArrayI
testArrayCopy = 0x600001780a50
&testArrayCopy = 0x7ffeee00e738

[testArrayMutableCopy class] = __NSArrayM
testArrayMutableCopy = 0x6000017b0270
&testArrayMutableCopy = 0x7ffeee00e718
   
从输出结果可以看出: 
(1)不可变容器调用copy方法, 其实只是把当前对象的指针指向了原对象的地址;
(2)调用mutableCopy方法, 则是新分配了一块内存区域, 并把新对象指向了这块区域;

2.2 可变容器对象调用Copy和MutableCopy; 如NSMutableArray

//可变数组的内存地址和指针地址
NSMutableArray *testMArray = [NSMutableArray arrayWithArray:@[@"1", @"2", @"3"]];
NSLog(@"testMArray = %p", testMArray);
NSLog(@"&testMArray = %p", &testMArray);

//可变数组copy后的内存地址和指针地址
id testMArrayCopy = testMArray.copy;
NSLog(@"[testMArrayCopy class] = %@",[testMArrayCopy class]);
NSLog(@"testMArrayCopy = %p",testMArrayCopy);
NSLog(@"&testMArrayCopy = %p", &testMArrayCopy);
   
//可变数组mutableCopy后的内存地址和指针地址
id testMArrayMutableCopy = testMArray.mutableCopy;
NSLog(@"[testMArrayMutableCopy class] = %@", [testMArrayMutableCopy class]);
NSLog(@"testMArrayMutableCopy = %p",testMArrayMutableCopy);
NSLog(@"&testMArrayMutableCopy = %p", &testMArrayMutableCopy);
  
输出结果:
testMArray = 0x600003950570
&testMArray = 0x7ffee41d9728

[testMArrayCopy class] = __NSArrayI
testMArrayCopy = 0x6000039547b0
&testMArrayCopy = 0x7ffee41d9730

[testMArrayMutableCopy class] = __NSArrayM
testMArrayMutableCopy = 0x60000395a160
&testMArrayMutableCopy = 0x7ffee41d9738  

从输出结果可以看出:
可变容器调用copy和mutableCopy方法后都会重新分配一块内存;

总结:
(1)非容器对象(NSString)
不可变对象调用copy方法其实只是把当前对象的指针指向了原对象的地址; 而调用mutableCopy方法则是重新分配了一块内存区域并把新对象的指针指向了这块区域;

可变对象调用copy和mutableCopy方法都会重新分配一块内存区域.

(2)容器类对象(NSArray)
容器对象本身和非容器对象是同样的效果.

参考: www.cnblogs.com/yxl-151217/…