[OC] OC中的深拷贝和浅拷贝

738 阅读3分钟

1: 什么是深浅拷贝

  • 苹果官方文档里:

There are two kinds of object copying: shallow copies and deep copies. The normal copy is a shallow copy that produces a new collection that shares ownership of the objects with the original. Deep copies create new objects from the originals and add those to the new collection.

翻译一下:

有两种类型的对象拷贝,浅拷贝和深拷贝。正常的拷贝,生成一个新的容器,但却是和原来的容器共用内部的元素,这叫做浅拷贝深拷贝不仅生成新的容器,还生成了新的内部元素。 有官方文档为证, 我们可以得知: 浅拷贝复制容器,深拷贝复制容器及其内部元素

OC提供了copymutablecopy方法,顾名思义, copy就是复制了一个imutable的对象,而mutablecopy就是复制了一个mutable的对象。

1: 系统的非容器类对象: 这里指的是NSString、NSNumber等等一类的对象。

    NSString *str= @"origion";

    NSString *strCp = [str copy];
    NSMutableString *strMCp = [str mutableCopy];
    [strMCp appendString:@"!!"];


    NSLog(@"str: %@", str);       // str: origion
    NSLog(@"strCp: %@", strCp);   // strCp: origion
    NSLog(@"strMCp: %@", strMCp); // strMCp: origion!!

    

    NSLog(@"str: %p", str);        // str: 0x100004020
    NSLog(@"strCp: %p", strCp);    // strCp: 0x100004020
    NSLog(@"strMCp: %p", strMCp);  // strMCp: 0x1010219d0
 
 }

调用copy之后系统并没有开辟新内存, 调用mutableCopy之后系统开辟了新内存, 所以对于这中非容器类对象来说:copy指的是浅拷贝, mutableCopy指的是深拷贝.

2: 系统的容器类对象, 指NSArray,NSDictionary等

  • 2.1 对于容器类本身上述结论也适用: 类型 | copy | mutableCopy | | -------------- | ---- | ----------- | | NSArray | 浅拷贝 | 深拷贝 | | NSMutableArray | 深拷贝 | 深拷贝
    NSArray *arr = [NSArray arrayWithObjects:@"a", nil];

    NSArray *arrCp = [arr copy];
    NSMutableArray *arrMCp = [arr mutableCopy];
    [arrMCp addObject:@"b"];

    
    NSLog(@"arr: %@", arr);        // arr: (a)
    NSLog(@"arrCp: %@", arrCp);    // arrCp: (a)
    NSLog(@"arrMCp: %@", arrMCp);  // arrMCp: (a, b)

    
    NSLog(@"arr: %p", arr);       // arr: 0x101114ed0
    NSLog(@"arrCp: %p", arrCp);   // arrCp: 0x101114ed0
    NSLog(@"arrMCp: %p", arrMCp); // arrMCp: 0x1011199d0
  • 2.2 容器内对象是深拷贝还是浅拷贝? 例如数组中嵌套数组:
    NSMutableArray *element = [NSMutableArray arrayWithObject:@1];
    NSMutableArray *arr = [NSMutableArray arrayWithObject:element];
    NSMutableArray *arrMCp = [arr mutableCopy];

    [arrMCp addObject:@2];
    [arrMCp[0] addObject:@3];


    NSLog(@"arr: %@", arr);       // arr:((1, 3))
    NSLog(@"arrMCp: %@", arrMCp); //arr:((1, 3), 2)

    
    NSLog(@"arr: %p", arr);       // arr: 0x105243120
    NSLog(@"arrMCp: %p", arrMCp); // arrMCp: 0x1052431f0


    NSLog(@"arr[0]: %p", arr[0]);       // arr[0]: 0x1052430f0
    NSLog(@"arrMCp[0]: %p", arrMCp[0]); // arrMCp[0]: 0x1052430f0

从上面的例子, 可以得出结论: 所有系统容器类内的对象copymutableCopy方法, 都是浅拷贝

  • 2.3 那么我们可以继续探索一下对于容器类内的对象该怎么实现深拷贝呢?
  • 方法1: 用系统中的 initWithArray:copyItems: 方法
  • 方法2: 用我们自定义的方法例如:
- (NSArray *)test_deepCopy {    
      NSMutableArray *array = [NSMutableArray array];  
      for (id element in self) {  
          id copyElement = nil;  
          if ([element respondsToSelector:@selector(test_deepCopy)]) {  
              copyElement = [element test_deepCopy];  
          }   
          else if ([element respondsToSelector:@selector(copyWithZone:)]) { 
              copyElement = [element copy];  
          }   
          else {  
              copyElement = element;   
          }   
          [array addObject:copyElement];  
      }   
      NSArray *result = [NSArray arrayWithArray:array];  
      return result;  
  }
  
- (NSMutableArray *)test_mutableDeepCopy { 
    NSMutableArray *array = [NSMutableArray array]for (id element in self) {  
        id copyElement = nil;  
          if ([element respondsToSelector:@selector(test_mutableDeepCopy)]) {  
              copyElement = [element test_mutableDeepCopy];  
          }   
          else if ([element respondsToSelector:@selector(mutableCopyWithZone:)           {  
              copyElement = [element mutableCopy];  
          }   
          else if ([element respondsToSelector:@selector(copyWithZone:)]) {  
              copyElement = [element copy];  
          }   
          else {  
              copyElement = element;   
          }   
          [array addObject:copyElement];  
      }   
      return array;  
}

3:Reference: