OC------深拷贝和浅拷贝

一,深拷贝和浅拷贝

1,深拷贝:内容拷贝,拷贝数据到一块新内存区域,指针指向拷贝的数据区域。(另外创建一个一摸一样的对象,新对象与原对象不共享内存,修改新对象不会改变原对象)

2,浅拷贝:指针拷贝,复制一个新指针,指针指向同一块内存区域。实际内存并没有发生拷贝(只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存)

深拷贝图像示意

OC------深拷贝和浅拷贝_第1张图片

浅拷贝图像示意 

OC------深拷贝和浅拷贝_第2张图片

 在Objective-C中并不是所有的对象(自定义类创建的对象)都支持Copy,MutableCopy,遵守NSCopying协议的类才可以发送Copy消息,遵守NSMutableCopying 协议的类才可以发送MutableCopy消息。

二,对非集合对象的copy和mutablecopy

以NSString类型为例

NSString *string1 = @"helloworld";
        NSString *string2 = [string1 copy];
        NSString *string3 = [string1 mutableCopy];
        NSMutableString *string4 = [string1 copy];
        NSMutableString *string5 = [string1 mutableCopy];
        NSLog(@"string1 = %p",string1);
        NSLog(@"string2 = %p",string2);
        NSLog(@"string3 = %p",string3);
        NSLog(@"string4 = %p",string4);
        NSLog(@"string5 = %p",string5);

OC------深拷贝和浅拷贝_第3张图片

string2和string4进行了浅拷贝,复制对象和被复制对象都不可改变,所以只复制了指针。

string3和string5进行了深拷贝,为了保证复制对象可以改变,所以即复制了指针又复制了所指的内容 

NSMutableString *string1 = [NSMutableString stringWithString:@"helloworld"];
        NSString *string2 = [string1 copy];
        NSString *string3 = [string1 mutableCopy];
        NSMutableString *string4 = [string1 copy];
        NSMutableString *string5 = [string1 mutableCopy];
        NSLog(@"string1 = %p",string1);
        NSLog(@"string2 = %p",string2);
        NSLog(@"string3 = %p",string3);
        NSLog(@"string4 = %p",string4);
        NSLog(@"string5 = %p",string5);

OC------深拷贝和浅拷贝_第4张图片

string2到string5都进行了深拷贝,为了保证被复制对象可以改变,无论复制对象是否可以改变,都复制了指针又复制了所指的内容 。

总结:

对immutable对象进行copy操作,是浅拷贝,mutablecopy操作时,是深拷贝;对mutabled对象进行copy和mutable copy,都是深拷贝。 

三,对集合元素的copy和mutable copy 

集合对象包括NSArray,NSSet,NSDictionary等类的对象 

以NSArray为例

NSArray *array01 = [NSArray arrayWithObjects:@"a", @"b", @"c", nil];
        NSArray *copyArray01 = [array01 copy];
        NSMutableArray *mutableCopyArray01 = [array01 mutableCopy];
        NSLog(@"array01 = %p", array01);
        NSLog(@"copyArray01 = %p", copyArray01);
        NSLog(@"mutableCopyArray01 = %p", mutableCopyArray01);

        NSLog(@"array01[0] = %p", array01[0]);
        NSLog(@"copyArray01[0] = %p", copyArray01[0]);
        NSLog(@"mutableCopyArray01[0] = %p", mutableCopyArray01[0]);

OC------深拷贝和浅拷贝_第5张图片

copyArray01进行了浅拷贝,复制对象和被复制对象都不可改变,所以只复制了指针。

mutableCopyArray01进行了深拷贝,为了保证复制对象可以改变,所以即复制了指针又复制了所指的内容 。

copyArray01和mutableCopyArray01集合内部的元素仍然是指针拷贝(浅拷贝)。

NSMutableArray *mutableArray01 = [NSMutableArray     arrayWithObjects:@"a",@"b",@"c", nil];
        NSArray *copyArray01 = [mutableArray01 copy];
        NSMutableArray *mutableCopyArray01 = [mutableArray01 mutableCopy];

        NSLog(@"mutableArray01 = %p", mutableArray01);
        NSLog(@"copyArray01 = %p", copyArray01);
        NSLog(@"mutableCopyArray01 = %p", mutableCopyArray01);

        [mutableArray01 addObject:@"d"];
        NSLog(@"mutableArray01 = %@", mutableArray01);
        NSLog(@"copyArray01 = %@", copyArray01);
        NSLog(@"mutableCopyArray01 = %@", mutableCopyArray01);

        NSLog(@"mutableArray01[0] = %p", mutableArray01[0]);
        NSLog(@"copyArray01[0] = %p", copyArray01[0]);
        NSLog(@"mutableCopyArray01[0] = %p", mutableCopyArray01[0]);

OC------深拷贝和浅拷贝_第6张图片

 copyArray01和mutableCopyArrat01都进行了深拷贝,为了保证被复制对象可以改变,无论复制对象是否可以改变,都复制了指针又复制了所指的内容 。

由于mutableArray是可变类型,可以对其集合添加元素,其集合里面的元素会增加,而copyArray01和mutableCopyArrat01都进行了深拷贝,它们集合里面的元素不会增加。

 copyArray01和mutableCopyArray01集合内部的元素仍然是指针拷贝(浅拷贝)。

总结:

在集合类对象中,对immutable对象进行copy,是浅拷贝,mutableCopy是深拷贝;对mutable对象进行copy和mutableCopy都是深拷贝。但是:集合对象的内容拷贝仅限于对象本身,对象元素仍然是浅拷贝。

四,完全拷贝

那么怎么对集合里面的元素也进行深拷贝呢? 

完全拷贝(real-deep copy):在完全拷贝操作时,对于被拷贝对象的每一层都是对象拷贝。 

例如数组完全深拷贝需要执行initWithArray:copyItems: 方法

NSArray *deepCopy = [[NSArray alloc] initWithArray:array copyItems:YES]

 我们要想对数组中的对象也进行深拷贝,要做到如下:

首先创建Person.hPerson.m,需要实现协议。

Person.h

#import 

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject
@property (nonatomic, strong) NSMutableString* name;
@end

NS_ASSUME_NONNULL_END

Person.m

#import "Person.h"

@implementation Person
@synthesize name;
- (id) copyWithZone:(NSZone *)zone {
    Person* person = [[[self class] allocWithZone:zone] init];
    person.name = [self.name mutableCopy];
    return  person;
}
@end

maim.n

#import 
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        /*--------数组元素拷贝-------*/
        NSLog(@"");
        NSLog(@"--不可变NSArray--元素拷贝--");
        Person *person = [[Person alloc] init];
        person.name = [NSMutableString stringWithString:@"one"];
        
        NSArray *array1 = [[NSArray alloc] initWithObjects:person, nil];
        //注意仅仅是这里更改为了[[NSArray alloc] initWithArray:array1 copyItems:YES];
        NSArray *array2 = [[NSArray alloc] initWithArray:array1 copyItems:YES];
        Person *p = array2[0];
        [p.name replaceCharactersInRange:NSMakeRange(0, 3) withString:@"two"];
        //获取两个数组里的各自Person对象
        Person *p1 = [array1 objectAtIndex:0];
        Person *p2 = [array2 objectAtIndex:0];
            
        NSLog(@"array1:%p",array1);
        NSLog(@"array2:%p",array2);
        NSLog(@"p1:%p",p1);
        NSLog(@"p2:%p",p2);
        NSLog(@"p1.name1:%p",p1.name);
        NSLog(@"p2.name2:%p",p2.name);
        NSLog(@"p1.name:%@",p1.name);
        NSLog(@"p2.name:%@",p2.name);
        
        NSLog(@"");
        NSLog(@"--可变NSMutableArray--元素拷贝--");
        Person *per = [[Person alloc] init];
        per.name = [NSMutableString stringWithString:@"one11"];
               NSMutableArray *array111 = [[NSMutableArray alloc] initWithObjects:person, nil];
        //注意仅仅是这里更改为了[[NSArray alloc] initWithArray:array1 copyItems:YES];
        NSMutableArray *array222 = [[NSMutableArray alloc] initWithArray:array111 copyItems:YES];
        Person *pp = array222[0];
        [pp.name replaceCharactersInRange:NSMakeRange(0, 3) withString:@"two11"];         //获取两个数组里的各自Person对象
        Person *p11 = [array111 objectAtIndex:0];
        Person *p22 = [array222 objectAtIndex:0];
            
        NSLog(@"array111:%p",array111);
        NSLog(@"array222:%p",array222);
        NSLog(@"p11:%p",p11);
        NSLog(@"p22:%p",p22);
        NSLog(@"p11.name:%@",p11.name);
        NSLog(@"p22.name:%@",p22.name);
    }
    return 0;
}

OC------深拷贝和浅拷贝_第7张图片

我们可以看出,不但array1array2的内存地址发生改变,连array2里面的Person对象的内存地址也发生改变,生成了另外一个Person对象。但person对象的name属性还没有确定深拷贝还是浅拷贝

你可能感兴趣的:(ios)