iOS常见问题(1)--浅拷贝与深拷贝
本人所有文章目录:http://my.oschina.net/ChenTF/blog/677112
本篇文章地址: http://my.oschina.net/ChenTF/blog/1789532
转载请注明出处
在开始之前, 先问几个问题:
- 对NSString执行copy后, 是深拷贝还是浅拷贝?
- 对NSMutableString执行copy后, 是深拷贝还是浅拷贝?
- 对数组进行Copy后, 是深拷贝还是浅拷贝?
- 对数组进行Copy后, 修改旧数组内指针执行对象的内容, 新数组对象内容是否改变?
- 对数组进行mutableCopy呢?
- NSArray *newArray = [[NSArray alloc] initWithArray:oldArray]. 对newArray的元素所指的指针进行操作, 会影响oldArray吗?
- 如何实现数组的内容Copy?
答案:
- 浅拷贝
- 深拷贝
- 浅拷贝
- 改变
- 浅拷贝, 改变
- 会影响
- initWithArray:copyItems:
如果你对以上问题都了然于心, 则请忽略本文.
以下是正文:
概念:
- 深拷贝 / 对象拷贝: 在有指针的情况下, 增加一个指针指向已经存在的内存 (OC中引用计数会+1)
- 浅拷贝 / 指针拷贝: 增加一个指针, 并且申请一个新的内存, 使新指针指向新内存.
1.对一个不可变对象执行Copy, MutableCopy时, 会发生什么?
TFLog宏:
#define TFLog(x) (NSLog(@"x = %p : %@, retainCount = %lu", x, x, x.retainCount))
NSString *str = @"origion";
NSString *stringCopy = [str copy];
NSMutableString *stringMCopy = [str mutableCopy];
[stringMCopy appendString:@"!!"];
TFLog(str);
TFLog(stringCopy);
TFLog(stringMCopy);
/* Log:
2018-04-02 11:47:00.496571+0800 StudyCopy[9955:783264] x = 0x10c795060 : origion, retainCount = 18446744073709551615
2018-04-02 11:47:00.496703+0800 StudyCopy[9955:783264] x = 0x10c795060 : origion, retainCount = 18446744073709551615
2018-04-02 11:47:00.496785+0800 StudyCopy[9955:783264] x = 0x600000256560 : origion!!, retainCount = 1
*/
从Log可以看出str与stringCopy的内存地址一致, stringMCopy与str的地址不一样
结论:
- copy是浅拷贝;
- mutableCopy是深拷贝
2.对一个可变对象执行Copy, MutableCopy时, 会发生什么?
NSMutableString *string = [NSMutableString stringWithString: @"origion"];
NSString *stringCopy = [string copy];
NSMutableString *mStringCopy = [string copy];
NSMutableString *stringMCopy = [string mutableCopy];
TFLog(string);
TFLog(stringCopy);
TFLog(mStringCopy);
TFLog(stringMCopy);
/* Log:
2018-04-02 15:51:16.104555+0800 StudyCopy[10470:931102] x = 0x60400044f870 : origion, retainCount = 1
2018-04-02 15:51:16.104712+0800 StudyCopy[10470:931102] x = 0xa6e6f696769726f7 : origion, retainCount = 18446744073709551615
2018-04-02 15:51:16.104806+0800 StudyCopy[10470:931102] x = 0xa6e6f696769726f7 : origion, retainCount = 18446744073709551615
2018-04-02 15:51:16.104889+0800 StudyCopy[10470:931102] x = 0x60400044ea30 : origion, retainCount = 1
*/
// [mStringCopy appendString:@"mm"]; //error: copy的结果是不可变对象
[string appendString:@" origion!"];
[stringMCopy appendString:@"!!"];
TFLog(string);
TFLog(stringCopy);
TFLog(mStringCopy);
TFLog(stringMCopy);
/* Log:
2018-04-02 15:53:54.796318+0800 StudyCopy[10490:933693] x = 0x60000025ab80 : origion origion!, retainCount = 1
2018-04-02 15:53:54.796453+0800 StudyCopy[10490:933693] x = 0xa6e6f696769726f7 : origion, retainCount = 18446744073709551615
2018-04-02 15:53:54.796531+0800 StudyCopy[10490:933693] x = 0xa6e6f696769726f7 : origion, retainCount = 18446744073709551615
2018-04-02 15:53:54.796605+0800 StudyCopy[10490:933693] x = 0x6000002593e0 : origion!!, retainCount = 1
*/
看Log1: mStringCopy , mStringCopy, stringMCopy, 三个的内存地址都不一样, 所以得出结论2.1
看Log2: 执行完appendString后, string与stringMCopy都重新分配了地址, 可得出结论
2.2
结论:
2.1 Mutable 的 Copy, mutableCopy 都是深拷贝
2.2 [NSMutableString appendString] 方法会抛弃之前的内存地址, 开辟新的内存地址, 然后赋值给当前对象;
2.3 copy返回的是不可变对象, mutableCopy是可变对象, 与深浅拷贝是两件事情.
3.4 无论是深拷贝, 还是浅拷贝, 都是为了保证执行Copy后, 修改任一一方, 对另一方不影响, 所以iMutable只需要实现浅拷贝即可, 而Mutable需要实现深拷贝才可以.
3. 对不可变/可变 数组进行Copy, mutableCopy, 是深拷贝还是浅拷贝?
//copy返回不可变对象,mutablecopy返回可变对象
NSArray *array1 = [[NSArray alloc] initWithArray:@[@"a", @"b", @"c", @"d"]];
NSArray *arrayCopy1 = [array1 copy];
NSMutableArray *mArrayCopy1 = [array1 mutableCopy];
NSLog(@" ============ 1 =============");
TFLog(array1);
TFLog(arrayCopy1);
TFLog(mArrayCopy1);
/* Log:
2018-04-03 15:31:06.168695+0800 StudyCopy[15196:1840616] x = 0x60000045a2e0 : (
a, 0x1097f20a0, retainCount = 18446744073709551615
b, 0x1097f20c0, retainCount = 18446744073709551615
c, 0x1097f20e0, retainCount = 18446744073709551615
d, 0x1097f2100, retainCount = 18446744073709551615
)
, retainCount = 2
2018-04-03 15:31:06.168841+0800 StudyCopy[15196:1840616] x = 0x60000045a2e0 : (
a, 0x1097f20a0, retainCount = 18446744073709551615
b, 0x1097f20c0, retainCount = 18446744073709551615
c, 0x1097f20e0, retainCount = 18446744073709551615
d, 0x1097f2100, retainCount = 18446744073709551615
)
, retainCount = 2
2018-04-03 15:31:06.168988+0800 StudyCopy[15196:1840616] x = 0x60000045cfb0 : (
a, 0x1097f20a0, retainCount = 18446744073709551615
b, 0x1097f20c0, retainCount = 18446744073709551615
c, 0x1097f20e0, retainCount = 18446744073709551615
d, 0x1097f2100, retainCount = 18446744073709551615
)
, retainCount = 1
结论:
3.1 Array 的copy是浅拷贝, mutableCopy虽然数组重新分配了内存, 但是元素内容不变, 浅拷贝
*/
NSLog(@" ============ 2 =============");
[mArrayCopy1 addObject:@"de"];
TFLog(mArrayCopy1);
/*Log:
2018-04-03 14:31:51.231321+0800 StudyCopy[14904:1800741] ============ 2 =============
2018-04-03 15:31:06.169435+0800 StudyCopy[15196:1840616] x = 0x60000045cfb0 : (
a, 0x1097f20a0, retainCount = 18446744073709551615
b, 0x1097f20c0, retainCount = 18446744073709551615
c, 0x1097f20e0, retainCount = 18446744073709551615
d, 0x1097f2100, retainCount = 18446744073709551615
de, 0x1097f2180, retainCount = 18446744073709551615
)
, retainCount = 1
)*/
NSLog(@" ============ 3 =============");
[mArrayCopy1 removeObjectAtIndex:0];
NSArray *array2 = [mArrayCopy1 copy];
NSMutableArray *array3 = [mArrayCopy1 mutableCopy];
TFLog(mArrayCopy1);
TFLog(array2);
TFLog(array3);
/*Log:
2018-04-03 15:38:47.577031+0800 StudyCopy[15234:1846891] x = 0x60400024aa10 : (
b, 0x101ebd0c0, retainCount = 18446744073709551615
c, 0x101ebd0e0, retainCount = 18446744073709551615
d, 0x101ebd100, retainCount = 18446744073709551615
de, 0x101ebd180, retainCount = 18446744073709551615
)
, retainCount = 1
2018-04-03 15:38:47.612703+0800 StudyCopy[15234:1846891] x = 0x60400024a860 : (
b, 0x101ebd0c0, retainCount = 18446744073709551615
c, 0x101ebd0e0, retainCount = 18446744073709551615
d, 0x101ebd100, retainCount = 18446744073709551615
de, 0x101ebd180, retainCount = 18446744073709551615
)
, retainCount = 1
2018-04-03 15:38:47.612841+0800 StudyCopy[15234:1846891] x = 0x60400024ab60 : (
b, 0x101ebd0c0, retainCount = 18446744073709551615
c, 0x101ebd0e0, retainCount = 18446744073709551615
d, 0x101ebd100, retainCount = 18446744073709551615
de, 0x101ebd180, retainCount = 18446744073709551615
)
, retainCount = 1
结论:
3.2 对MArray进行add, 或 remove, 并不会改变数组的指针, 只会更改数组内的元素
3.3 [MutableArray copy] 是浅拷贝 [MutableArray mutableCopy] 也是浅拷贝, 内容不变
*/
通过分析Log1中 array1, arrayCopy1的地址一致, 可得出 不可变数组 copy是浅拷贝;
通过分析Log1中 array1, mArrayCopy1的地址不一致, 但内部元素地址一样. -> 可得出 不可变数组 mutableCopy是浅拷贝;
通过分析Log3中 mArrayCopy1, array2, array3的地址不一致, 但内部元素地址一样. 可得出: 可变数组, copy, mutableCopy都是浅拷贝
结论:
3.1 Array 的copy是浅拷贝, mutableCopy虽然数组重新分配了内存, 但是元素内容不变, 浅拷贝;
3.2 对MArray进行add, 或 remove, 并不会改变数组的指针, 只会更改数组内的元素
3.3 [MutableArray copy] 是浅拷贝 [MutableArray mutableCopy] 也是浅拷贝,
3.4 数组无论是copy, 还是mutableCopy, 内部元素地址都不变, 都是浅拷贝
4.如何实现数组内容的拷贝?
为了保证非系统对NSString进行了优化, 所以自定义了Person类:
@interface Person : NSObject<NSCopying, NSMutableCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSUInteger *age;
- (instancetype)initWithName:(NSString *)name Age:(NSUInteger)age;
@end
@implementation Person
- (instancetype)initWithName:(NSString *)name Age:(NSUInteger)age {
self = [super init];
if (self) {
_name = [name copy];
_age = age;
}
return self;
}
- (id)copyWithZone:(NSZone *)zone {
NSLog(@"person copyWithZone 被调用");
Person *p = [[Person allocWithZone:zone] init];//[self copyWithZone:zone];
p.name = [self.name copy];
p.age = self.age;
return p;
}
- (id)mutableCopyWithZone:(nullable NSZone *)zone {
NSLog(@"person mutableCopyWithZone 被调用");
Person *p = [[Person allocWithZone:zone] init];//[self copyWithZone:zone];
p.name = [self.name copy];
p.age = self.age;
return p;
}
@end
测试:
Person *p1 = [[Person alloc] initWithName:@"小明" Age:11];
Person *p2 = [[Person alloc] initWithName:@"小明" Age:22];
Person *p3 = [[Person alloc] initWithName:@"小红" Age:11];
Person *p4 = [[Person alloc] initWithName:@"小红" Age:22];
NSArray *array1 = [NSArray arrayWithObjects:p1, p2, p3, p4, nil];
NSArray *array2 = [array1 copy];
NSMutableArray *mArray1 = [array1 mutableCopy];
NSMutableArray *mArray2 = [mArray1 mutableCopy];
NSArray *array3 = [mArray1 copy];
NSLog(@" ============ 1 =============");
TFLog(array1);
TFLog(array2);
TFLog(mArray1);
TFLog(mArray2);
TFLog(array3);
/*
2018-04-03 16:16:02.203387+0800 StudyCopy[15501:1883285] ============ 1 =============
2018-04-03 16:16:02.204392+0800 StudyCopy[15501:1883285] x = 0x60000025ed20 : (
<Person: 0x600000421040>, 0x600000421040, retainCount = 3
<Person: 0x600000421020>, 0x600000421020, retainCount = 3
<Person: 0x600000420fe0>, 0x600000420fe0, retainCount = 3
<Person: 0x6000004210a0>, 0x6000004210a0, retainCount = 3
)
, retainCount = 2
2018-04-03 16:16:02.204560+0800 StudyCopy[15501:1883285] x = 0x60000025ed20 : (
<Person: 0x600000421040>, 0x600000421040, retainCount = 3
<Person: 0x600000421020>, 0x600000421020, retainCount = 3
<Person: 0x600000420fe0>, 0x600000420fe0, retainCount = 3
<Person: 0x6000004210a0>, 0x6000004210a0, retainCount = 3
)
, retainCount = 2
2018-04-03 16:16:02.204733+0800 StudyCopy[15501:1883285] x = 0x60000025f200 : (
<Person: 0x600000421040>, 0x600000421040, retainCount = 3
<Person: 0x600000421020>, 0x600000421020, retainCount = 3
<Person: 0x600000420fe0>, 0x600000420fe0, retainCount = 3
<Person: 0x6000004210a0>, 0x6000004210a0, retainCount = 3
)
, retainCount = 1
2018-04-03 16:16:02.204862+0800 StudyCopy[15501:1883285] x = 0x60000025f140 : (
<Person: 0x600000421040>, 0x600000421040, retainCount = 3
<Person: 0x600000421020>, 0x600000421020, retainCount = 3
<Person: 0x600000420fe0>, 0x600000420fe0, retainCount = 3
<Person: 0x6000004210a0>, 0x6000004210a0, retainCount = 3
)
, retainCount = 1
2018-04-03 16:16:02.205016+0800 StudyCopy[15501:1883285] x = 0x60000025eff0 : (
<Person: 0x600000421040>, 0x600000421040, retainCount = 3
<Person: 0x600000421020>, 0x600000421020, retainCount = 3
<Person: 0x600000420fe0>, 0x600000420fe0, retainCount = 3
<Person: 0x6000004210a0>, 0x6000004210a0, retainCount = 3
)
, retainCount = 1
*/
结论:
4.1 对可变, 不可变数组执行 copy, mutableCopy的结果都不会影响数组内的元素, 数组内元素仍是浅拷贝.
4.2 无论执行的是 initWithArray 方法还是Copy, 结果都一致
Example:
NSLog(@" ============ 2 =============");
NSArray *array11 = [[NSArray alloc] initWithArray:array1];
NSArray *array12 = [[NSArray alloc] initWithArray:array1 copyItems:YES];
NSMutableArray *mArray11 = [[NSMutableArray alloc] initWithArray:array1];
NSMutableArray *mArray12 = [[NSMutableArray alloc] initWithArray:array1 copyItems:YES];
TFLog(array11);
TFLog(array12);
TFLog(mArray11);
TFLog(mArray12);
/* Log:
2018-04-03 16:16:02.205103+0800 StudyCopy[15501:1883285] ============ 2 =============
2018-04-03 16:28:50.427949+0800 StudyCopy[15578:1895787] person copyWithZone 被调用
2018-04-03 16:28:50.428040+0800 StudyCopy[15578:1895787] person copyWithZone 被调用
2018-04-03 16:28:50.428109+0800 StudyCopy[15578:1895787] person copyWithZone 被调用
2018-04-03 16:28:50.428197+0800 StudyCopy[15578:1895787] person copyWithZone 被调用
2018-04-03 16:28:50.428434+0800 StudyCopy[15578:1895787] person copyWithZone 被调用
2018-04-03 16:28:50.428556+0800 StudyCopy[15578:1895787] person copyWithZone 被调用
2018-04-03 16:28:50.429276+0800 StudyCopy[15578:1895787] person copyWithZone 被调用
2018-04-03 16:28:50.429357+0800 StudyCopy[15578:1895787] person copyWithZone 被调用
2018-04-03 16:16:05.699864+0800 StudyCopy[15501:1883285] x = 0x60400024e6a0 : (
<Person: 0x600000421040>, 0x600000421040, retainCount = 5
<Person: 0x600000421020>, 0x600000421020, retainCount = 5
<Person: 0x600000420fe0>, 0x600000420fe0, retainCount = 5
<Person: 0x6000004210a0>, 0x6000004210a0, retainCount = 5
)
, retainCount = 1
2018-04-03 16:16:05.700044+0800 StudyCopy[15501:1883285] x = 0x60400024e940 : (
<Person: 0x604000236600>, 0x604000236600, retainCount = 1
<Person: 0x604000236400>, 0x604000236400, retainCount = 1
<Person: 0x604000236760>, 0x604000236760, retainCount = 1
<Person: 0x604000236640>, 0x604000236640, retainCount = 1
)
, retainCount = 1
2018-04-03 16:16:05.700265+0800 StudyCopy[15501:1883285] x = 0x60400024e700 : (
<Person: 0x600000421040>, 0x600000421040, retainCount = 5
<Person: 0x600000421020>, 0x600000421020, retainCount = 5
<Person: 0x600000420fe0>, 0x600000420fe0, retainCount = 5
<Person: 0x6000004210a0>, 0x6000004210a0, retainCount = 5
)
, retainCount = 1
2018-04-03 16:16:05.700456+0800 StudyCopy[15501:1883285] x = 0x60400024e9a0 : (
<Person: 0x604000236680>, 0x604000236680, retainCount = 1
<Person: 0x6040002366a0>, 0x6040002366a0, retainCount = 1
<Person: 0x6040002365e0>, 0x6040002365e0, retainCount = 1
<Person: 0x604000236700>, 0x604000236700, retainCount = 1
)
, retainCount = 1
结论:
4.2 NSArray想实现数组内容也拷贝, 只有通过 initWithArray:copyItems: 方法才可以 ,
同时 会间接调用copyWithZon:的方法, mutableCopyWithZone:不会调用
*/
4.3 通过 array1 , array12, marray22的 元素内容的地址都不相同, 可知
4.4 initWithArray:copyItems: 会调用NSCoping协议的copyWithZone方法, 达到内容拷贝的效果.
回顾总结:
对象:
- 不可变 copy -> 浅拷贝; mutableCopy -> 深拷贝
- 可变 copy -> 深拷贝; mutableCopy -> 深拷贝
数组:
- 不可变 copy -> 浅拷贝; mutableCopy -> 浅拷贝
- 可变 copy -> 浅拷贝; mutableCopy -> 浅拷贝
数组的copy 内容都不会进行深拷贝
觉得对你有帮助, 想请我喝杯果汁?
支付宝收钱码