Shallow Copy & Deep Copy

对象的拷贝需要首先实现协议

浅拷贝:object Aobject B及其属性使用同样的内存地址,简单说明的话,可以认为是指针复制;
深拷贝:object Aobject 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
}

结论

  • 自定义对象的copymsg进行了浅拷贝

自定义对象的嵌套

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

结论

  • 自定义对象的copymutableCopy方法,多层嵌套的子类进行了深拷贝,多层嵌套子类的NSString属性msg进行了copymutableCopy

容器类的拷贝

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对象,都没有进行拷贝
  • CommonCopy2ClasscopyWithZone没有执行
  • 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对象,都没有进行拷贝
  • CommonCopy2ClasscopyWithZone没有执行
  • 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

你可能感兴趣的:(Shallow Copy & Deep Copy)