文章目录
  1. 1. 前言
  2. 2. 深拷贝与浅拷贝
  3. 3. 知识点
  4. 4. 参考资料
  5. 5. 文档信息

前言


关于拷贝,小到面试题,大到找不出 Bugs。

在 iOS 中分为 浅拷贝 和 深拷贝,对应 Foundation 中的基本数据类型,系统已经实现和遵循了 NSCopying 协议和方法。下面大家来了解一下。

深拷贝与浅拷贝


1
2
3
4
5
6
7
8
9
10
11
@protocol NSCopying

- (id)copyWithZone:(nullable NSZone *)zone;

@end

@protocol NSMutableCopying

- (id)mutableCopyWithZone:(nullable NSZone *)zone;

@end

区别:
浅拷贝:指针拷贝,共用一个内存地址。
深拷贝:新的指针,新的内存地址。

不可变对象进行 copy, 不会生成新的对象(类型:eg:NSString),共用一个地址。
可变对对象进行 copy, 会生成新的对象(类型:eg:NSMutableString),新的内存地址。

1
2
3
4
5
6
NSString * oldStr = @"older";
NSString * newStr = [oldStr copy];
NSLog(@"%p - %p - %@", oldStr, newStr, [oldStr class]);
oldStr = [oldStr stringByAppendingString:@"12"];//生成新的对象,并指向新的指针地址
NSLog(@"%@ - %@ - %@", oldStr, newStr, [newStr class]);
NSLog(@"%p - %p", oldStr, newStr);

1
2
3
0x1021e40d8 - 0x1021e40d8 - __NSCFConstantString
older12 - older - __NSCFConstantString
0x600002229bf0 - 0x1021e40d8
1
2
3
4
5
6
NSMutableString * oldMStr = [NSMutableString stringWithString:@"mutableStr"];
NSMutableArray * newMStr = [oldMStr copy];
NSLog(@"%p - %p - %@", oldMStr, newMStr, [oldMStr class]);
[oldMStr appendString:@"-M"];//指针地址不变
NSLog(@"%@ - %@ - %@", oldMStr, newMStr, [newMStr class]);
NSLog(@"%p - %p", oldMStr, newMStr);
1
2
3
0x6000022297a0 - 0x600002c422e0 - __NSCFString
mutableStr-M - mutableStr - __NSCFString
0x6000022297a0 - 0x600002c422e0

不可变对象进行 mutableCopy, 会生成新的对象(类型:eg:NSMutableString),新的内存地址。
可变对象进行 mutableCopy, 会生成新的对象(类型:eg:NSMutableString),新的内存地址。

1
2
3
4
5
6
NSArray * oldArr = [NSArray arrayWithObject:@"array"];
NSArray * newArr = [oldArr mutableCopy];
NSLog(@"%p - %p - %@", oldArr, oldArr, [oldArr class]);
oldArr = [oldArr arrayByAddingObject:@"-arr"];//新的对象,新的内存地址
NSLog(@"%ld - %ld - %@", oldArr.count, newArr.count, [newArr class]);
NSLog(@"%p - %p", oldArr, newArr);

1
2
3
0x600002e73c50 - 0x600002e73c50 - __NSSingleObjectArrayI
2 - 1 - __NSArrayM
0x600002c42260 - 0x600002233d80
1
2
3
4
5
6
NSMutableArray * oldMArr = [NSMutableArray arrayWithObject:@"mutableArray"];
NSMutableArray * newMArr = [oldMArr mutableCopy];
NSLog(@"%p - %p - %@", oldMArr, newMArr, [oldMArr class]);
[oldMArr addObject:@"-arr"];//内存地址不变
NSLog(@"%ld - %ld - %@", oldMArr.count, newMArr.count, [newMArr class]);
NSLog(@"%p - %p", oldMArr, newMArr);
1
2
3
0x600002229830 - 0x600002229e30 - __NSArrayM
2 - 1 - __NSArrayM
0x600002229830 - 0x600002229e30

对于自定义对象,若要使用 copy 或 mutableCopy 需要遵循协议,实现协议方法。

知识点


Q: 在 property 中,为什么常用 copy 修饰 string 字符串,而不用 strong 修饰?

分析:首先 Strong 会指向内存地址,如果用 strong 修饰可变字符时,当指向的内存地址发生变化时,属性中的值也会相应变化;copy 修饰,相当于对象进行浅拷贝(self.obja = [objb copy])。

1
2
@property (nonatomic, copy) NSString * string0;
@property (nonatomic, strong) NSString * string1;

对应不可变的字符串来说,相当于浅拷贝,指针拷贝。

1
2
3
4
5
NSString * string0 = @"string0";
self.string0 = string0;
self.string1 = string0;
string0 = @"0";//指针地址发生变化
NSLog(@"%p, %p, %p", self.string0, self.string1, string0);

1
0x10c59c098, 0x10c59c098, 0x10c59c0b8

对应可变的字符串来说,copy 修饰相当于深拷贝,strong 修饰为指针拷贝。

1
2
@property (nonatomic, copy) NSMutableString * mString0;
@property (nonatomic, strong) NSMutableString * mString1;

1
2
3
4
5
NSMutableString * pMstr = [NSMutableString stringWithString:@"string"];
self.mString0 = pMstr;
self.mString1 = pMstr;
[pMstr appendString:@"- cs"];
NSLog(@"%p, %p, %p", self.mString0, self.mString1, pMstr);
1
0xdd890020b715b501, 0x600000ba9da0, 0x600000ba9da0

A:对应不可变的字符串来说,相当于浅拷贝,指针拷贝;对应可变的字符串来说,copy 修饰相当于深拷贝,strong 修饰为指针拷贝。若不想属性成员变量随着变化,请用 copy 修饰。

参考资料


文档信息


  • 版权声明:自由转载-保持署名-非商用-非衍生 ( CC BY-NC-ND 4.0 )
文章目录
  1. 1. 前言
  2. 2. 深拷贝与浅拷贝
  3. 3. 知识点
  4. 4. 参考资料
  5. 5. 文档信息