美文网首页
iOS常见问题(1)--浅拷贝与深拷贝

iOS常见问题(1)--浅拷贝与深拷贝

作者: advancer_chen | 来源:发表于2018-04-03 21:56 被阅读342次

    本人所有文章目录:http://my.oschina.net/ChenTF/blog/677112
    本篇文章地址: http://my.oschina.net/ChenTF/blog/1789532
    转载请注明出处

    在开始之前, 先问几个问题:

    1. 对NSString执行copy后, 是深拷贝还是浅拷贝?
    2. 对NSMutableString执行copy后, 是深拷贝还是浅拷贝?
    3. 对数组进行Copy后, 是深拷贝还是浅拷贝?
    4. 对数组进行Copy后, 修改旧数组内指针执行对象的内容, 新数组对象内容是否改变?
    5. 对数组进行mutableCopy呢?
    6. NSArray *newArray = [[NSArray alloc] initWithArray:oldArray]. 对newArray的元素所指的指针进行操作, 会影响oldArray吗?
    7. 如何实现数组的内容Copy?

    答案:

    1. 浅拷贝
    2. 深拷贝
    3. 浅拷贝
    4. 改变
    5. 浅拷贝, 改变
    6. 会影响
    7. 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 内容都不会进行深拷贝


    觉得对你有帮助, 想请我喝杯果汁?

    微信收钱码
    支付宝收钱码

    相关文章

      网友评论

          本文标题:iOS常见问题(1)--浅拷贝与深拷贝

          本文链接:https://www.haomeiwen.com/subject/jkfhhftx.html