iOS FAQ (1): Shallow copy and deep copy

Catalog of all my articles: http://my.oschina.net/ChenTF/blog/677112
Address of this article: http://my.oschina.net/ChenTF/blog/1789532
Please indicate the source for reprinting

Before we start, take a quiz:

  1. After copying NSString, is it a deep copy or a shallow copy?
  2. After copying NSMutableString, is it a deep copy or a shallow copy?
  3. After copying the array, is it a deep copy or a shallow copy?
  4. After copying the array, modify the content pointed to by the pointer object in the old array, does the content of the new array object change?
  5. What about mutableCopy an array?
  6. NSArray *newArray = [[NSArray alloc] initWithArray:oldArray]. Does the operation on the pointer pointed to by the elements of newArray affect the oldArray?
  7. How to copy the contents of the array? (one-dimensional array)

Answer:

  1. shallow copy
  2. deep copy
  3. shallow copy
  4. Change
  5. deep copy, change
  6. will affect
  7. initWithArray:copyItems:

Disputed point: The content of the array is a list of pointers. When mutableCopy is performed on the array, the content of the array has opened up a new space for copying. I think it is already a deep copy for the array object. Of course, some students feel that there is no point to the array. The object is reallocated, not a deep copy.

If you answered all of the above questions correctly, please ignore this article.

Here is the text :


concept:

  • Shallow copy/pointer copy: if there is another pointer, add a pointer to the existing memory (the reference count in OC will be +1)
  • Deep copy/object copy: add a pointer, and allocate a new memory, making the new pointer point to the new memory.

1. What happens when Copy, MutableCopy is performed on an immutable object?

     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
     */

It can be seen from the Log that the memory addresses of str and stringCopy are the same, and the addresses of stringMCopy and str are different

in conclusion:

  • copy is a shallow copy;
  • mutableCopy is a deep copy

2. What happens when Copy, MutableCopy is performed on a mutable object?

     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
     */

Look at Log1: mStringCopy, mStringCopy, stringMCopy, the memory addresses of the three are different, so come to the conclusion 2.1
Look at Log2: After executing appendString, both string and stringMCopy have reallocated addresses, and you can draw the conclusion 2.2

Conclusion:
2.1 Mutable's Copy, mutableCopy are deep copy
2.2 [NSMutableString appendString] method will discard the previous memory address, open up a new memory address, and then assign it to the current object;
2.3 copy returns an immutable object, mutableCopy is variable Objects, and deep and shallow copies are two different things.
3.4 Whether it is a deep copy or a shallow copy, it is to ensure that after the copy is executed, modifying either side will not affect the other side, so iMutable only needs to implement a shallow copy, And Mutable needs to implement deep copy to do it.

3. Copy, mutableCopy, deep copy or shallow copy for immutable/mutable arrays?

    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] 也是深拷贝, 内容不变
     */

By analyzing the consistent addresses of array1 and arrayCopy1 in Log1, it can be concluded that the immutable array copy is a shallow copy;
by analyzing the inconsistent addresses of array1 and mArrayCopy1 in Log1, it can be concluded that the immutable array mutableCopy is a deep copy;
by analyzing mArrayCopy1 in Log3, The addresses of array2 and array3 are inconsistent, and it can be concluded that: mutable array, copy, mutableCopy are all deep copies

Conclusion:
3.1 Array copy is a shallow copy, mutableCopy is a deep copy, but the content remains unchanged
3.2 Adding or removing MArray does not change the pointer of the array, but only changes the elements in the array
3.3 [MutableArray copy] is deep Copy [MutableArray mutableCopy] is also a deep copy, the content remains unchanged
3.4 No matter whether the array is a deep copy or a shallow copy, it only copies the pointers and objects of the array, and the elements in the array are all shallow copies

4. How to copy the contents of the array?

In order to ensure that the non-system optimizes NSString, the Person class is customized:

@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

Example:

    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
     */

in conclusion:

4.1 Execute copy on mutable and immutable arrays. The result of mutableCopy will not affect the elements in the array, and the elements in the array are still shallow copies.
No matter whether the initWithArray method or Copy is executed, the results are the same

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:不会调用
     */

Conclusion:
The addresses of the elements of array1, array12, and marray22 are different. It can be seen that initWithArray:copyItems: will call the copyWithZone method of the NSCoping protocol to achieve the effect of content copying.

Review summary:

Object:

immutable copy -> shallow copy; mutableCopy -> deep copy
mutable copy -> deep copy; mutableCopy -> deep copy

array:

immutable copy -> shallow copy; mutableCopy -> deep copy
mutable copy -> deep copy; mutableCopy -> deep copy

Copy the array, the contents will not be deeply copied


Thought it would be helpful to you and would like to invite me for a glass of juice?
WeChat payment code Alipay receipt code

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324446908&siteId=291194637