对象的拷贝需要首先实现
或
协议
浅拷贝:
object A
和object B
及其属性使用同样的内存地址,简单说明的话,可以认为是指针复制;
深拷贝:object A
和object B
及其属性使用不同的内存地址,简单说明的话,可以认为是内容复制。
自定义对象的拷贝
CommonClass
// CommonClass.h
@interface CommonClass : NSObject
@property (nonatomic, copy) NSString *msg;
@end
// CommonClass.m
@implementation CommonClass
- (instancetype)init{
self = [super init];
if (self) {
self.msg = @"CommonClass";
}
return self;
}
- (id)copyWithZone:(NSZone *)zone{
CommonClass *aObj = [[[self class] allocWithZone:zone] init];
aObj.msg = self.msg;
return aObj;
}
@end
接下来做copy测试
void copy(void) {
CommonClass *obj1 = [[CommonClass alloc] init];
NSLog(@"obj1 %p, msg:%p", obj1, obj1.msg);
>>> obj1 0x105904360, msg:0x10000ce58
CommonClass *obj2 = [obj1 copy];
NSLog(@"obj2 %p, msg:%p", obj2, obj2.msg);
>>> obj2 0x105906080, msg:0x10000ce58
}
结论
- 自定义对象的
copy
,msg
进行了浅拷贝
自定义对象的嵌套
CommonCopyClass
// CommonCopyClass.h
@interface CommonCopyClass : NSObject
@property (nonatomic, strong) CommonClass *objA;
@property (nonatomic, copy) NSString *msg;
@end
// CommonCopyClass.m
@implementation CommonCopyClass
- (instancetype)init{
self = [super init];
if (self) {
self.objA = [[CommonClass alloc] init];
self.msg = @"msg";
}
return self;
}
- (id)copyWithZone:(NSZone *)zone{
CommonCopyClass *aObj = [[[self class] allocWithZone:zone] init];
aObj.objA = [self.objA copy];
aObj.msg = self.msg;
return aObj;
}
@end
CommonCopy2Class
// CommonCopy2Class.h
@interface CommonCopy2Class : NSObject
@property (nonatomic, strong) CommonCopyClass *objCopyA;
@end
// CommonCopy2Class.m
@implementation CommonCopy2Class
- (instancetype)init{
self = [super init];
if (self) {
self.objCopyA = [[CommonCopyClass alloc] init];
}
return self;
}
- (id)copyWithZone:(NSZone *)zone{
CommonCopy2Class *aObj = [[[self class] allocWithZone:zone] init];
aObj.objCopyA = [self.objCopyA copy];
return aObj;
}
@end
copy测试
CommonCopyClass *obj4 = [[CommonCopyClass alloc] init];
NSLog(@"obj4 %p, param:%p, subMsg:%p", obj4, obj4.objA, obj4.objA.msg);
>>> obj4 0x105906610, param:0x105906570, subMsg:0x10000ce58
CommonCopyClass *obj5 = [obj4 copy];
NSLog(@"obj5 %p, param:%p, subMsg:%p", obj5, obj5.objA, obj5.objA.msg);
>>> obj5 0x105804160, param:0x105804290, subMsg:0x10000ce58
CommonCopy2Class *obj7 = [[CommonCopy2Class alloc] init];
NSLog(@"obj7 %p, param:%p, subParam:%p, subsubMsg:%p", obj7, obj7.objCopyA, obj7.objCopyA.objA, obj7.objCopyA.objA.msg);
>>> obj7 0x100607fd0, param:0x1058040d0, subParam:0x105804180, subsubMsg:0x10000ce58
CommonCopy2Class *obj8 = [obj7 copy];
NSLog(@"obj8 %p, param:%p, subParam:%p, subsubMsg:%p", obj8, obj8.objCopyA, obj8.objCopyA.objA, obj8.objCopyA.objA.msg);
>>> obj8 0x1058040c0, param:0x1058044b0, subParam:0x1058044e0, subsubMsg:0x10000ce58
结论
- 自定义对象的
copy
和mutableCopy
方法,多层嵌套的子类进行了深拷贝,多层嵌套子类的NSString
属性msg进行了copy
和mutableCopy
容器类的拷贝
NSArray的拷贝
void arrayCopy(void) {
CommonCopy2Class *obj1 = [[CommonCopy2Class alloc] init];
CommonCopy2Class *obj2 = [[CommonCopy2Class alloc] init];
NSLog(@"obj1 %p, obj2 %p", obj1, obj2);
>>> obj1 0x105c040c0, obj2 0x105c04230
NSArray *a1 = @[obj1, obj2];
NSLog(@"a1 %@, %p, item:%@",NSStringFromClass([a1 class]), a1, a1);
>>> a1 __NSArrayI, 0x10062fcd0, "", ""
NSArray *a2 = [a1 copy];
NSLog(@"a2 %@, %p, item:%@",NSStringFromClass([a2 class]), a2, a2);
>>> a2 __NSArrayI, 0x10062fcd0, "", ""
NSArray *a3 = [a1 mutableCopy];
NSLog(@"a3 %@, %p, item:%@",NSStringFromClass([a3 class]), a3, a3);
>>> a3 __NSArrayM, 0x100507500, "", ""
NSMutableArray *ma1 = [[NSMutableArray alloc] initWithArray:a1];
NSLog(@"ma1 %@, %p, item:%@",NSStringFromClass([ma1 class]), ma1, ma1);
>>> ma1 __NSArrayM, 0x10125ba70, "", ""
NSMutableArray *ma2 = [ma1 copy];
NSLog(@"ma2 %@, %p, item:%@",NSStringFromClass([ma2 class]), ma2, ma2);
>>> ma2 __NSArrayI, 0x100606940, "", ""
NSMutableArray *ma3 = [ma1 mutableCopy];
NSLog(@"ma3 %@, %p, item:%@",NSStringFromClass([ma3 class]), ma3, ma3);
>>> ma3 __NSArrayM, 0x100708fe0, "", ""
}
结论
- 无论是
NSCopy
或是NSMutableCopy
,容器内的CommonCopy2Class
对象,都没有进行拷贝 -
CommonCopy2Class
的copyWithZone
没有执行 - NSArray
-
NSArray
对象的copy
方法,返回__NSArrayI
对象,浅拷贝 -
NSArray
对象的NSMutableCopy
方法,返回__NSArrayM
对象,是一个可变数组。对数组进行了第一层的深拷贝
-
- NSMutableArray
-
NSMutableArray
对象的copy
方法,返回__NSArrayI
对象,不再可变,对原有数组进行了第一层深拷贝 -
NSMutableArray
对象的NSMutableCopy
方法,返回__NSArrayM
对象,是一个可变数组,对原有数组进行了第一层深拷贝
-
NSDictionary
void dictionaryCopy(void) {
CommonCopy2Class *obj1 = [[CommonCopy2Class alloc] init];
CommonCopy2Class *obj2 = [[CommonCopy2Class alloc] init];
NSLog(@"obj1 %p, obj2 %p", obj1, obj2);
>>> obj1 0x101916b70, obj2 0x101904160
NSDictionary *d1 = @{@"1": obj1, @"2": obj2};
NSLog(@"d1 %@, %p, item:%@",NSStringFromClass([d1 class]), d1, d1);
>>> d1 __NSDictionaryI, 0x101c09b70, "", ""
NSDictionary *d2 = [d1 copy];
NSLog(@"d2 %@, %p, item:%@",NSStringFromClass([d2 class]), d2, d2);
>>> d2 __NSDictionaryI, 0x101c09b70, "", ""
NSDictionary *d3 = [d1 mutableCopy];
NSLog(@"d3 %@, %p, item:%@",NSStringFromClass([d3 class]), d3, d3);
>>> d3 __NSDictionaryM, 0x1019172e0, "", ""
NSMutableDictionary *md1 = [[NSMutableDictionary alloc] initWithDictionary:d1];
NSLog(@"md1 %@, %p, item:%@",NSStringFromClass([md1 class]), md1, md1);
>>> md1 __NSDictionaryM, 0x101840690, "", ""
NSMutableDictionary *md2 = [md1 copy];
NSLog(@"md2 %@, %p, item:%@",NSStringFromClass([md2 class]), md2, md2);
>>> md2 __NSFrozenDictionaryM, 0x101843ba0, "", ""
NSMutableDictionary *md3 = [md1 mutableCopy];
NSLog(@"md3 %@, %p, item:%@",NSStringFromClass([md3 class]), md3, md3);
>>> md3 __NSDictionaryM, 0x1006068e0, "", ""
}
结论
- 无论是
NSCopy
或是NSMutableCopy
,容器内的CommonCopy2Class
对象,都没有进行拷贝 -
CommonCopy2Class
的copyWithZone
没有执行 - NSDictionary
-
NSDictionary
对象的copy
方法,返回__NSDictionaryM
对象,浅拷贝 -
NSDictionary
对象的NSMutableCopy
方法,返回__NSDictionaryM
对象,是一个可变字典,第一层深拷贝
-
- NSMutableDictionary
-
NSMutableDictionary
对象的copy
方法,返回__NSFrozenDictionaryM
对象。虽然是M结尾,但他并不是一个可变的字典类。对原有的字典进行了第一层深拷贝 -
NSMutableDictionary
对象的NSMutableCopy
方法,返回__NSDictionaryM
对象,是一个可变数组,对原有字典进行了第一层深拷贝
-
copyItems
void initCopy(void) {
CommonCopy2Class *obj1 = [[CommonCopy2Class alloc] init];
CommonCopy2Class *obj2 = [[CommonCopy2Class alloc] init];
NSLog(@"obj1 %p, obj2 %p", obj1, obj2);
>>> obj1 0x1005089c0, obj2 0x10053bf80
NSLog(@"obj1 %p, param:%p, subParam:%p, subsubParam:%p", obj1, obj1.objCopyA, obj1.objCopyA.objA, obj1.objCopyA.objA.msg); // 输出1
>>> obj1 0x1005089c0, param:0x100546490, subParam:0x10053d870, subsubMsg:0x10000ceb8
NSArray *a1 = @[obj1, obj2];
NSLog(@"a1 %@, %p, item:%@",NSStringFromClass([a1 class]), a1, a1);
>>> a1 __NSArrayI, 0x100546af0, "", ""
NSArray *a2 = [[NSArray alloc] initWithArray:a1 copyItems:YES];
NSLog(@"a2 %@, %p, item:%@",NSStringFromClass([a2 class]), a2, a2);
>>> a2 __NSArrayI, 0x100546b90, "", ""
CommonCopy2Class *obj3 = a2.firstObject;
NSLog(@"obj3 %p, param:%p, subParam:%p, subsubParam:%p", obj3, obj3.objCopyA, obj3.objCopyA.objA, obj3.objCopyA.objA.msg); // 输出2
>>> obj3 0x100546a20, param:0x100546ef0, subParam:0x10053ce40, subsubMsg:0x10000ceb8
NSMutableArray *ma1 = [[NSMutableArray alloc] initWithArray:a1 copyItems:YES];
NSLog(@"ma1 %@, %p, item:%@",NSStringFromClass([ma1 class]), ma1, ma1);
>>> ma1 __NSArrayM, 0x106104480, "", ""
CommonCopy2Class *obj4 = ma1.firstObject;
NSLog(@"obj4 %p, param:%p, subParam:%p, subsubParam:%p", obj4, obj4.objCopyA, obj4.objCopyA.objA, obj4.objCopyA.objA.msg); // 输出3
>>> obj4 0x106104340, param:0x106104380, subParam:0x1061043b0, subsubMsg:0x10000ceb8
NSDictionary *d1 = @{@"1": obj1, @"2": obj2};
NSLog(@"d1 %@, %p, item:%@",NSStringFromClass([d1 class]), d1, d1);
>>> d1 __NSDictionaryI, 0x100704450, 1 = ""; 2 = "";
NSDictionary *d2 = [[NSDictionary alloc] initWithDictionary:d1 copyItems:YES];
NSLog(@"d2 %@, %p, item:%@",NSStringFromClass([d2 class]), d2, d2);
>>> d2 __NSDictionaryI, 0x1063050b0, 1 = ""; 2 = "";
CommonCopy2Class *obj5 = d2[@"1"];
NSLog(@"obj5 %p, param:%p, subParam:%p, subsubParam:%p", obj5, obj5.objCopyA, obj5.objCopyA.objA, obj5.objCopyA.objA.msg);
>>> obj5 0x106304e00, param:0x106304e40, subParam:0x106305190, subsubMsg:0x10000ceb8
NSMutableDictionary *md1 = [[NSMutableDictionary alloc] initWithDictionary:d1 copyItems:YES];
NSLog(@"md1 %@, %p, item:%@",NSStringFromClass([md1 class]), md1, md1);
>>> md1 __NSDictionaryM, 0x106504090, 1 = ""; 2 = "";
CommonCopy2Class *obj6 = md1[@"1"];
NSLog(@"obj6 %p, param:%p, subParam:%p, subsubParam:%p", obj6, obj6.objCopyA, obj6.objCopyA.objA, obj6.objCopyA.objA.msg);
>>> obj6 0x106504080, param:0x1065040c0, subParam:0x1065040f0, subsubMsg:0x10000ceb8
}
结论
-
copyItems
会对容器内部的元素进行copy
操作,即对元素进行了深拷贝。
容器的嵌套
void nestedCopy (void) {
CommonCopy2Class *obj1 = [[CommonCopy2Class alloc] init];
CommonCopy2Class *obj2 = [[CommonCopy2Class alloc] init];
CommonCopy2Class *obj3 = [[CommonCopy2Class alloc] init];
NSLog(@"obj1 %p, obj2 %p ,obj3 %p", obj1, obj2, obj3); // 输出1
>>> obj1 0x105a04100, obj2 0x105a04560 ,obj3 0x105a045a0
NSArray *oa1 = @[obj1, obj2];
NSArray *oa2 = @[obj3];
NSLog(@"oa1 %p, oa2 %p", oa1, oa2); // 输出2
>>> oa1 0x105a04710, oa2 0x105a04730
NSArray *a1 = @[oa1, oa2];
NSLog(@"a1 %p", a1);
>>> a1 0x105a045e0
NSArray *a2 = [a1 copy];
NSLog(@"a2 %p", a2); // 输出3
>>> a2 0x105a045e0
NSArray *a3 = [[NSArray alloc] initWithArray:a1 copyItems:YES];
NSLog(@"a3 %p", a3);
>>> a3 0x105a04600
NSLog(@"oa1 %p, oa2 %p", a3.firstObject, a3.lastObject); // 输出6
>>> oa1 0x105a04710, oa2 0x105a04730
NSMutableArray *ma1 = [[NSMutableArray alloc] initWithArray:a1];
NSLog(@"oa1 %p, oa2 %p", ma1.firstObject, ma1.lastObject);
>>> oa1 0x105a04710, oa2 0x105a04730
NSMutableArray *ma2 = [[NSMutableArray alloc] initWithArray:ma1 copyItems:YES];
NSLog(@"oa1 %p, oa2 %p", ma2.firstObject, ma2.lastObject); // 输出7
>>> oa1 0x105a04710, oa2 0x105a04730
CommonCopy2Class *obj6 = ((NSArray *)ma2.firstObject).firstObject;
NSLog(@"obj6 %p, param:%p, subParam:%p, subsubParam:%p", obj6, obj6.objCopyA, obj6.objCopyA.objA, obj6.objCopyA.objA.msg);
>>> obj6 0x105a04100, param:0x105a04190, subParam:0x105a04490, subsubParam:0x10000ceb8
}
结论
- 如果
NSArray
的元素是NSArray
类型(这里是和NSMutableArray
做区分,可能是__NSArrayI
类型)subArray是同一个
补充
void nestedCopy2 (void) {
CommonCopy2Class *obj1 = [[CommonCopy2Class alloc] init];
CommonCopy2Class *obj2 = [[CommonCopy2Class alloc] init];
CommonCopy2Class *obj3 = [[CommonCopy2Class alloc] init];
NSLog(@"obj1 %p, obj2 %p ,obj3 %p", obj1, obj2, obj3);
NSMutableArray *ma1 = [[NSMutableArray alloc] initWithObjects:obj1, obj2, nil];
NSMutableArray *ma2 = [[NSMutableArray alloc] initWithObjects:obj3, nil];
NSArray *sa1 = [[NSArray alloc] initWithObjects:ma1, ma2, nil];
NSLog(@"%@ %p", sa1, sa1.firstObject);
NSArray *sa2 = [[NSArray alloc] initWithArray:sa1 copyItems:YES];
NSLog(@"%@ %p", sa2, sa2.firstObject);
}
(
(
"",
""
),
(
""
)
) 0x100746c70
(
(
"",
""
),
(
""
)
) 0x100746f30