美文网首页
iOS 浅copy和深copy区别

iOS 浅copy和深copy区别

作者: 木子雨廷t | 来源:发表于2020-02-21 21:54 被阅读0次
    浅copy :拷贝的是对象本身,两个对象指向同一块内存空间。
    深copy :重新开辟内存空间,两个对象指向不同的内存空间。
    浅copy图示
    浅copy图示
    深copy图示
    深copy图示

    从上图可以看出,浅拷贝A指针改变了所指向的内容,B指针也指向被修改后的内容。如果有些地方用到B指针,不希望在A指向的内容发生变化时也跟着变化,则需要用到深拷贝。
    通俗理解为:浅拷贝好比你的影子,你死了,影子也没了;深拷贝好比克隆人,你死了,它还在。

    本质区别

    深拷贝和浅拷贝的本质是地址是否相同

    在开发过程中,大体上会区分为对象和容器两个概念,对象的copy是浅拷贝,mutablecopy是深拷贝。
    容器包含对象的拷贝,无论是copy,还是mutablecopy都是浅拷贝,要想实现对象的深拷贝,必须自己提供拷贝方法。

    1. 非容器不可变对象:NSString
    2. 非容器可变对象: NSMutableString
    3. 容器类不可变对象: NSArray
    4. 容器类可变对象: NSMutableArray
    对四种类型对象分别举例
    非容器不可变对象
        NSString *str1 = @"非容器不可变对象";
        NSString *str2 = [str1 copy];
        NSString *str3 = [str1 mutableCopy];
        
        NSLog(@"str1_p : %p, class: %@", str1, [str1 class]);
        NSLog(@"str2_p : %p, class: %@", str2, [str2 class]);
        NSLog(@"str3_p : %p, class: %@", str3, [str3 class]);
    

    输出

    str1_p : 0x104c4a068, class: __NSCFConstantString
    str2_p : 0x104c4a068, class: __NSCFConstantString
    str3_p : 0x61000006db00, class: __NSCFString
    

    结论:

    对于非容器不可变对象的copy为浅拷贝,mutableCopy为深拷贝
    浅拷贝获得的对象地址和原对象地址一致, 返回的对象为不可变对象
    深拷贝返回新的内存地址,返回对象为可变对象

    非容器可变对象
        NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
        NSMutableString *str2 = [str1 copy];
        NSMutableString *str3 = [str1 mutableCopy];
        
        NSLog(@"str1_p : %p, class: %@", str1, [str1 class]);
        NSLog(@"str2_p : %p, class: %@", str2, [str2 class]);
        NSLog(@"str3_p : %p, class: %@", str3, [str3 class]);
    

    输出

    str1_p : 0x618000260140, class: __NSCFString
    str2_p : 0x61800004efd0, class: __NSCFString
    str3_p : 0x6180002602c0, class: __NSCFString
    

    结论:

    对于非容器可变对象的copy为深拷贝
    mutableCopy为深拷贝
    并且copy和mutableCopy返回对象都为可变对象

    容器不可变对象
        NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
        
        NSArray *array = [NSArray arrayWithObjects:str1, @"非容器不可变对象", nil];
        NSArray *copyArray = [array copy];
        NSArray *mutableCopyArray = [array mutableCopy];
        
        NSLog(@"array_p: %p, class: %@", array, [array class]);
        NSLog(@"copyArray_p: %p, class: %@", copyArray, [copyArray class]);
        NSLog(@"mutableCopyArray_p: %p, class: %@", mutableCopyArray, [mutableCopyArray class]);
        
        NSLog(@"======原对象=====");
        NSLog(@"object_p: %p, class: %@", array[0], [array[0] class]);
        NSLog(@"object_p: %p, class: %@", array[1], [array[1] class]);
        
        NSLog(@"======copy对象=====");
        NSLog(@"object_p: %p, class: %@", copyArray[0], [copyArray[0] class]);
        NSLog(@"object_p: %p, class: %@", copyArray[1], [copyArray[1] class]);
        
        NSLog(@"======mutableCopy对象=====");
        NSLog(@"object_p: %p, class: %@", mutableCopyArray[0], [mutableCopyArray[0] class]);
        NSLog(@"object_p: %p, class: %@", mutableCopyArray[1], [mutableCopyArray[1] class]);
    

    输出:

    array_p: 0x610000024ac0, class: __NSArrayI
    copyArray_p: 0x610000024ac0, class: __NSArrayI
    mutableCopyArray_p: 0x610000242610, class: __NSArrayM
    
    ======原对象=====
    object_p: 0x61000006f540, class: __NSCFString
    object_p: 0x10c386080, class: __NSCFConstantString
    
    ======copy对象=====
    object_p: 0x61000006f540, class: __NSCFString
    object_p: 0x10c386080, class: __NSCFConstantString
    
    ======mutableCopy对象=====
    object_p: 0x61000006f540, class: __NSCFString
    object_p: 0x10c386080, class: __NSCFConstantString
    

    结论:
    从上述输出中可以看出容器类不可变对象mutableCopy确实返回一个新的容器,但容器内的元素仍然是浅拷贝

    容器可变对象
        NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
        
        NSMutableArray *array = [NSMutableArray arrayWithObjects:str1, @"非容器不可变对象", nil];
        NSMutableArray *copyArray = [array copy];
        NSMutableArray *mutableCopyArray = [array mutableCopy];
        
        NSLog(@"array_p: %p, class: %@", array, [array class]);
        NSLog(@"copyArray_p: %p, class: %@", copyArray, [copyArray class]);
        NSLog(@"mutableCopyArray_p: %p, class: %@", mutableCopyArray, [mutableCopyArray class]);
        
        NSLog(@"======原对象=====");
        NSLog(@"object_p: %p, class: %@", array[0], [array[0] class]);
        NSLog(@"object_p: %p, class: %@", array[1], [array[1] class]);
        
        NSLog(@"======copy对象=====");
        NSLog(@"object_p: %p, class: %@", copyArray[0], [copyArray[0] class]);
        NSLog(@"object_p: %p, class: %@", copyArray[1], [copyArray[1] class]);
        
        NSLog(@"======mutableCopy对象=====");
        NSLog(@"object_p: %p, class: %@", mutableCopyArray[0], [mutableCopyArray[0] class]);
        NSLog(@"object_p: %p, class: %@", mutableCopyArray[1], [mutableCopyArray[1] class]);
    

    输出:

    array_p: 0x6100000552d0, class: __NSArrayM
    copyArray_p: 0x610000031340, class: __NSArrayI
    mutableCopyArray_p: 0x610000055000, class: __NSArrayM
    
    ======原对象=====
    object_p: 0x610000267300, class: __NSCFString
    object_p: 0x107070080, class: __NSCFConstantString
    
    ======copy对象=====
    object_p: 0x610000267300, class: __NSCFString
    object_p: 0x107070080, class: __NSCFConstantString
    
    ======mutableCopy对象=====
    object_p: 0x610000267300, class: __NSCFString
    object_p: 0x107070080, class: __NSCFConstantString
    

    结论:
    从上述输出中可以看出容器类可变对象mutableCopy和copy都返回一个新的容器,但容器内的元素仍然是浅拷贝

    总结:

    通过上述代码分析:

    copy: 对于可变对象为深拷贝,对于不可变对象为浅拷贝
    mutableCopy:始终是深拷贝

    自定义类对象的深浅拷贝

    在OC中不是所有的类都支持拷贝,只有遵循<NSCopying>才支持copy,只有遵循<NSMutableCopying>才支持mutableCopy。如果没有遵循,拷贝时会直接Crash。
    代码:

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject <NSCopying, NSMutableCopying>
    
    @property (nonatomic, copy) NSString *name;
    
    @end
    
    
    #import "Person.h"
    
    @implementation Person
    
    - (id)copyWithZone:(NSZone *)zone {
        Person *person = [Person allocWithZone:zone];
        person.name = self.name;
        return person;
    }
    
    - (id)mutableCopyWithZone:(NSZone *)zone {
        Person *person = [Person allocWithZone:zone];
        person.name = self.name;
        return person;
    }
    
    @end
    
    实现容器对象的完全拷贝
    NSMutableString *str1 = [NSMutableString stringWithFormat:@"非容器可变对象"];
        NSArray *array = [NSArray arrayWithObjects:str1, @"非容器不可变对象", nil];
        
        NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithArray:array copyItems:YES];
        
        NSData *data = [NSKeyedArchiver archivedDataWithRootObject:mutableArray];
        NSMutableArray *newMutableArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
        
        NSLog(@"===原对象===");
        NSLog(@"array[0] : %p, array[1] : %p", array[0], array[1]);
        
        NSLog(@"===新对象===");
        NSLog(@"mutableArray[0] : %p, mutableArray[1] : %p", mutableArray[0], mutableArray[1]);
        
        NSLog(@"===完全拷贝对象===");
        NSLog(@"newMutableArray[0] : %p, newMutableArray[1] : %p", newMutableArray[0], newMutableArray[1]);
    

    输出:

    ===原对象===
    array[0] : 0x6180000697c0, array[1] : 0x10f40f098
    
    ===新对象===
    mutableArray[0] : 0x618000055060, mutableArray[1] : 0x10f40f098
    
    ===完全拷贝对象===
    newMutableArray[0] : 0x618000055600, newMutableArray[1] : 0x6180000556f0
    

    如果是自定义类对象 需要遵循<NSCoding>否则在使用NSKeyedArchiver的时候会Crash
    自定义对象代码如下

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject <NSCoding>
    
    @property (nonatomic, copy) NSString *name;
    
    @end
    
    
    #import "Person.h"
    
    @implementation Person
    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        return self;
    }
    
    - (void)encodeWithCoder:(NSCoder *)aCoder {
        [aCoder encodeObject:self.name forKey:@"name"];
    }
    
    @end
    

    相关文章

      网友评论

          本文标题:iOS 浅copy和深copy区别

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