浅拷贝和深拷贝

浅拷贝和深拷贝的区别在于拷贝后是重新复制了一个新对象,还是说只是增加了一个新的指向原对象的指针.

这里以字符串和数组,字典为例.

1.对于不可变的字符串,数组和字典来说,向其发送 copy 信息,即[obj copy],拷贝后得到的是一个不可变的对象,并且拷贝并没有将原对象进行复制.这是浅拷贝.

//对于不可变的 NSString, NSArray, NSDictionary,进行拷贝,是浅拷贝,得到的是不可变的对象
    NSString * str = [NSString stringWithFormat:@"hello world"];
    NSLog(@"str 引用计数 %lu", [str retainCount]);
    NSLog(@"str 地址 %p", str);
    
    NSString * newstr = [str copy];     //浅拷贝,原对象内容并没有再复制一份,只是拷贝出一个新指针,指向同一对象.因此原对象的引用计数+1.
    NSLog(@"newstr 引用计数%lu", [newstr retainCount]);
    NSLog(@"copy 后 str 引用计数 %lu", [str retainCount]);
    NSLog(@"newstr 地址 %p", newstr);
打印结果如下:

2015-02-05 17:13:23.259 LessonUI08Control[3652:154482] str 引用计数 1
2015-02-05 17:13:23.260 LessonUI08Control[3652:154482] str 地址 0x7ff3b97315e0
2015-02-05 17:13:23.260 LessonUI08Control[3652:154482] newstr 引用计数2
2015-02-05 17:13:23.260 LessonUI08Control[3652:154482] copy 后 str 引用计数 2
2015-02-05 17:13:23.260 LessonUI08Control[3652:154482] newstr 地址 0x7ff3b97315e0
可以看出,拷贝后 newstr 的地址和 str 的地址是一样的,说明 str 并没用完全复制一份, 只是新多了一个指针指向它,因此 str 的引用计数+1.

2.对于不可变的字符串,数组和字典来说,向其发送 mutableCopy 信息,即[objmutableCopy],拷贝后得到的是一个可变的对象,并且拷贝结果是对原对象进行了复制,得到了一个新的和原对象完全相同的新对象.这是深拷贝

NSString * str = [NSString stringWithFormat:@"hello world"];
    NSLog(@"str 引用计数 %lu", [str retainCount]);
    NSLog(@"str 地址 %p", str);
    NSMutableString * newstr = [str mutableCopy];    //使用 mutableCopy 可以进行深拷贝,并且拷贝出的字符串是可变的.
    NSLog(@"newstr 引用计数 %lu", [newstr retainCount]);
    [newstr deleteCharactersInRange:NSMakeRange(2, 2)];
    NSLog(@"str 引用计数 %lu", [str retainCount]);
    NSLog(@"newstr 地址 %p", newstr);
    NSLog(@"%@", newstr);
打印结果如下:

2015-02-05 17:17:46.487 LessonUI08Control[3680:155935] str 引用计数 1
2015-02-05 17:17:46.487 LessonUI08Control[3680:155935] str 地址 0x7fbc82c8b300
2015-02-05 17:17:46.487 LessonUI08Control[3680:155935] newstr 引用计数 1
2015-02-05 17:17:46.488 LessonUI08Control[3680:155935] str 引用计数 1
2015-02-05 17:17:46.488 LessonUI08Control[3680:155935] newstr 地址 0x7fbc82f11ff0
2015-02-05 17:17:46.488 LessonUI08Control[3680:155935] heo world
可以看出,拷贝后 newstr 的地址和 str 的地址不一样,说明 newstr 指向的是一个新对象,并且 str 的引用计数并没有增加, newstr 指向一个新对象,引用计数+1.并且拷贝后得到的 newstr 是可变的,可以对其进行修改.

3.向可变字符串,数组,字典发送 copy 信息,拷贝是深拷贝,返回的是不可变对象.

NSMutableString * str = [NSMutableString stringWithFormat:@"hello world"];
    NSLog(@"str 引用计数 %lu", [str retainCount]);
    NSLog(@"str 地址 %p", str);
    
    NSString * newstr = [str copy];  //深拷贝,原对象内容完全复制一份新的, newstr 保存新对象的地址,新对象引用计数+1.
    NSLog(@"newstr 引用计数 %lu", [newstr retainCount]);
    NSLog(@"newstr 地址 %p", newstr);
//    [newstr deleteCharactersInRange:NSMakeRange(2, 2)];     //会报错,因为拷贝出来的 newstr 是不可变的
    NSLog(@"%@", newstr);

打印结果如下:

2015-02-05 17:31:47.737 LessonUI08Control[3767:160881] str 引用计数 1
2015-02-05 17:31:47.738 LessonUI08Control[3767:160881] str 地址 0x7fb593f0af70
2015-02-05 17:31:47.738 LessonUI08Control[3767:160881] newstr 引用计数 1
2015-02-05 17:31:47.738 LessonUI08Control[3767:160881] newstr 地址 0x7fb593e0b930
2015-02-05 17:31:47.738 LessonUI08Control[3767:160881] hello world
可以看出 newstr 和 str 的地址是不同的,并且 str 的引用计数没有因为 copy 而增加

4.对可变字符串,数组,字典发送 mutableCopy 信息,得到的是深拷贝,并且返回的对象也是可变的.


总之, copy 返回的是不可变对象, mutableCopy 返回的是可变对象.

copy 用在不可变和可变对象上都是浅拷贝,

mutableCopy 用在可变和不可变对象上都是深拷贝.


应用举例

假设现在有一个 Person 类, Person 有一个属性 name.

@property (nonatomic, retain)NSString * name;        //这里先定义为 retain

这里,虽然我们要求的 name 是一个不可变字符串,但并不能保证别人在使用我们的类的时候为 name 赋值一个可变字符串.如下:

Person * p1 = [[Person alloc] init];
    NSMutableString * str = [NSMutableString stringWithFormat:@"mike"];
    p1.name = str;      //当 name 属性设置为 copy 的时候,进行赋值的时候会执行 _name = [name copy],即会进行一次拷贝,而且对于可变字符串来说,是深拷贝,因此属性 _name 指向的是一个新对象,对原对象 str 进行的任何更改都不会影响 _name 的值
    [str deleteCharactersInRange:NSMakeRange(2, 2)];
    [p1 sayhi];//打印 name 的值
    [p1 release];
    NSLog(@"str = %@", str);
str 是一个可变字符串,在为 name 赋值之后,又对 str 进行了更改,打印后结果如下:

2015-02-05 17:41:40.035 LessonUI08Control[3806:163843] name = mi
2015-02-05 17:41:40.036 LessonUI08Control[3806:163843] str = mi
我们发现, name 的值因为 str 的变化而发生了变化,这是因为现在 name 和 str 指向的是同一个对象,当对该对象进行了更改,会影响他们2个的值,这显然不是我们希望看到的.为了避免这种情况出现,我们就需要将属性修饰符改为 copy, 从而保证 name 中所存的是一个 str 的副本.当改为 copy 后,属性 name 的 setter 方法如下:

- (void)setName:(NSString *)name
{
    if (_name != name) {
        [_name release];
        _name = [name copy];
    }
}
可以看出,当传入的 name 是一个可变对象的时候, copy 后就能得到一个新的完全相同的对象.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值